@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.
@@ -11,7 +11,7 @@
11
11
  (function (global, factory) {
12
12
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('use-sync-external-store/shim')) :
13
13
  typeof define === 'function' && define.amd ? define(['exports', 'react', 'use-sync-external-store/shim'], factory) :
14
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactLocation = {}, global.React, global.shim));
14
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactRouter = {}, global.React, global.shim));
15
15
  })(this, (function (exports, React, shim) { 'use strict';
16
16
 
17
17
  function _interopNamespace(e) {
@@ -1321,6 +1321,40 @@
1321
1321
  return router.state.actions[id];
1322
1322
  })();
1323
1323
 
1324
+ const loader = router.state.loaders[id] || (() => {
1325
+ router.state.loaders[id] = {
1326
+ pending: [],
1327
+ fetch: async loaderContext => {
1328
+ if (!route) {
1329
+ return;
1330
+ }
1331
+
1332
+ const loaderState = {
1333
+ loadedAt: Date.now(),
1334
+ loaderContext
1335
+ };
1336
+ loader.current = loaderState;
1337
+ loader.latest = loaderState;
1338
+ loader.pending.push(loaderState); // router.state = {
1339
+ // ...router.state,
1340
+ // currentAction: loaderState,
1341
+ // latestAction: loaderState,
1342
+ // }
1343
+
1344
+ router.notify();
1345
+
1346
+ try {
1347
+ return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
1348
+ } finally {
1349
+ loader.pending = loader.pending.filter(d => d !== loaderState); // router.removeActionQueue.push({ loader, loaderState })
1350
+
1351
+ router.notify();
1352
+ }
1353
+ }
1354
+ };
1355
+ return router.state.loaders[id];
1356
+ })();
1357
+
1324
1358
  let route = {
1325
1359
  routeId: id,
1326
1360
  routeRouteId: routeId,
@@ -1331,6 +1365,7 @@
1331
1365
  childRoutes: undefined,
1332
1366
  parentRoute: parent,
1333
1367
  action,
1368
+ loader: loader,
1334
1369
  buildLink: options => {
1335
1370
  return router.buildLink(_extends({}, options, {
1336
1371
  from: fullPath
@@ -1426,12 +1461,10 @@
1426
1461
  isPending: false,
1427
1462
  isFetching: false,
1428
1463
  isInvalid: false,
1464
+ invalidAt: Infinity,
1429
1465
  getIsInvalid: () => {
1430
- var _ref, _routeMatch$options$l;
1431
-
1432
1466
  const now = Date.now();
1433
- const maxAge = (_ref = (_routeMatch$options$l = routeMatch.options.loaderMaxAge) != null ? _routeMatch$options$l : router.options.defaultLoaderMaxAge) != null ? _ref : 0;
1434
- return routeMatch.isInvalid || routeMatch.updatedAt + maxAge < now;
1467
+ return routeMatch.isInvalid || routeMatch.invalidAt < now;
1435
1468
  },
1436
1469
  __: {
1437
1470
  abortController: new AbortController(),
@@ -1520,9 +1553,33 @@
1520
1553
  routeMatch.isInvalid = true;
1521
1554
  },
1522
1555
  hasLoaders: () => {
1523
- return !!(route.options.loader || route.options.import || elementTypes.some(d => typeof route.options[d] === 'function'));
1556
+ return !!(route.options.loader || elementTypes.some(d => typeof route.options[d] === 'function'));
1524
1557
  },
1525
- load: async () => {
1558
+ load: async loaderOpts => {
1559
+ const now = Date.now();
1560
+ 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
1561
+
1562
+ if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
1563
+ // If the match is currently active, don't preload it
1564
+ if (router.state.matches.find(d => d.matchId === routeMatch.matchId)) {
1565
+ return;
1566
+ }
1567
+
1568
+ router.matchCache[routeMatch.matchId] = {
1569
+ gc: now + loaderOpts.gcMaxAge,
1570
+ match: routeMatch
1571
+ };
1572
+ } // If the match is invalid, errored or idle, trigger it to load
1573
+
1574
+
1575
+ if (routeMatch.status === 'success' && routeMatch.getIsInvalid() || routeMatch.status === 'error' || routeMatch.status === 'idle') {
1576
+ const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
1577
+ routeMatch.fetch({
1578
+ maxAge
1579
+ });
1580
+ }
1581
+ },
1582
+ fetch: async opts => {
1526
1583
  const id = '' + Date.now() + Math.random();
1527
1584
  routeMatch.__.latestId = id; // If the match was in an error state, set it
1528
1585
  // to a loading state again. Otherwise, keep it
@@ -1541,21 +1598,7 @@
1541
1598
  routeMatch.__.resolve = resolve;
1542
1599
 
1543
1600
  const loaderPromise = (async () => {
1544
- const importer = routeMatch.options.import; // First, run any importers
1545
-
1546
- if (importer) {
1547
- routeMatch.__.importPromise = importer({
1548
- params: routeMatch.params // search: routeMatch.search,
1549
-
1550
- }).then(imported => {
1551
- routeMatch.__ = _extends({}, routeMatch.__, imported);
1552
- });
1553
- } // Wait for the importer to finish before
1554
- // attempting to load elements and data
1555
-
1556
-
1557
- await routeMatch.__.importPromise; // Next, load the elements and data in parallel
1558
-
1601
+ // Load the elements and data in parallel
1559
1602
  routeMatch.__.elementsPromise = (async () => {
1560
1603
  // then run all element and data loaders in parallel
1561
1604
  // For each element type, potentially load it asynchronously
@@ -1566,17 +1609,14 @@
1566
1609
  return;
1567
1610
  }
1568
1611
 
1569
- if (typeof routeElement === 'function') {
1570
- const res = await routeElement(routeMatch);
1571
- routeMatch.__[type] = res;
1572
- } else {
1573
- routeMatch.__[type] = routeMatch.options[type];
1574
- }
1612
+ routeMatch.__[type] = await router.options.createElement(routeElement);
1575
1613
  }));
1576
1614
  })();
1577
1615
 
1578
1616
  routeMatch.__.dataPromise = Promise.resolve().then(async () => {
1579
1617
  try {
1618
+ var _ref, _ref2, _opts$maxAge;
1619
+
1580
1620
  if (routeMatch.options.loader) {
1581
1621
  const data = await routeMatch.options.loader({
1582
1622
  params: routeMatch.params,
@@ -1594,6 +1634,7 @@
1594
1634
  routeMatch.error = undefined;
1595
1635
  routeMatch.status = 'success';
1596
1636
  routeMatch.updatedAt = Date.now();
1637
+ 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);
1597
1638
  } catch (err) {
1598
1639
  if (id !== routeMatch.__.latestId) {
1599
1640
  return routeMatch.__.loaderPromise;
@@ -1716,13 +1757,15 @@
1716
1757
  const originalOptions = _extends({
1717
1758
  defaultLoaderGcMaxAge: 5 * 60 * 1000,
1718
1759
  defaultLoaderMaxAge: 0,
1719
- defaultLinkPreloadDelay: 50
1760
+ defaultPreloadMaxAge: 2000,
1761
+ defaultPreloadDelay: 50
1720
1762
  }, userOptions, {
1721
1763
  stringifySearch: (_userOptions$stringif = userOptions == null ? void 0 : userOptions.stringifySearch) != null ? _userOptions$stringif : defaultStringifySearch,
1722
1764
  parseSearch: (_userOptions$parseSea = userOptions == null ? void 0 : userOptions.parseSearch) != null ? _userOptions$parseSea : defaultParseSearch
1723
1765
  });
1724
1766
 
1725
1767
  let router = {
1768
+ history,
1726
1769
  options: originalOptions,
1727
1770
  listeners: [],
1728
1771
  removeActionQueue: [],
@@ -1741,6 +1784,7 @@
1741
1784
  location: null,
1742
1785
  matches: [],
1743
1786
  actions: {},
1787
+ loaders: {},
1744
1788
  loaderData: {},
1745
1789
  lastUpdated: Date.now(),
1746
1790
  isFetching: false,
@@ -1765,21 +1809,22 @@
1765
1809
  router.listeners.forEach(listener => listener());
1766
1810
  },
1767
1811
  mount: () => {
1768
- const next = router.buildLocation({
1812
+ const next = router.__.buildLocation({
1769
1813
  to: '.',
1770
1814
  search: true,
1771
1815
  hash: true
1772
1816
  }); // If the current location isn't updated, trigger a navigation
1773
1817
  // to the current location. Otherwise, load the current location.
1774
1818
 
1819
+
1775
1820
  if (next.href !== router.location.href) {
1776
- router.commitLocation(next, true);
1821
+ router.__.commitLocation(next, true);
1777
1822
  } else {
1778
1823
  router.loadLocation();
1779
1824
  }
1780
1825
 
1781
1826
  const unsub = history.listen(event => {
1782
- router.loadLocation(router.parseLocation(event.location, router.location));
1827
+ router.loadLocation(router.__.parseLocation(event.location, router.location));
1783
1828
  }); // addEventListener does not exist in React Native, but window does
1784
1829
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1785
1830
 
@@ -1809,169 +1854,11 @@
1809
1854
 
1810
1855
  if (routeConfig) {
1811
1856
  router.routesById = {};
1812
- router.routeTree = router.buildRouteTree(routeConfig);
1857
+ router.routeTree = router.__.buildRouteTree(routeConfig);
1813
1858
  }
1814
1859
 
1815
1860
  return router;
1816
1861
  },
1817
- buildRouteTree: rootRouteConfig => {
1818
- const recurseRoutes = (routeConfigs, parent) => {
1819
- return routeConfigs.map(routeConfig => {
1820
- const routeOptions = routeConfig.options;
1821
- const route = createRoute(routeConfig, routeOptions, parent, router); // {
1822
- // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
1823
- // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
1824
- // }
1825
-
1826
- const existingRoute = router.routesById[route.routeId];
1827
-
1828
- if (existingRoute) {
1829
- {
1830
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
1831
- }
1832
-
1833
- throw new Error();
1834
- }
1835
- router.routesById[route.routeId] = route;
1836
- const children = routeConfig.children;
1837
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
1838
- return route;
1839
- });
1840
- };
1841
-
1842
- const routes = recurseRoutes([rootRouteConfig]);
1843
- return routes[0];
1844
- },
1845
- parseLocation: (location, previousLocation) => {
1846
- var _location$hash$split$;
1847
-
1848
- const parsedSearch = router.options.parseSearch(location.search);
1849
- return {
1850
- pathname: location.pathname,
1851
- searchStr: location.search,
1852
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
1853
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
1854
- href: "" + location.pathname + location.search + location.hash,
1855
- state: location.state,
1856
- key: location.key
1857
- };
1858
- },
1859
- buildLocation: function buildLocation(dest) {
1860
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
1861
-
1862
- if (dest === void 0) {
1863
- dest = {};
1864
- }
1865
-
1866
- // const resolvedFrom: Location = {
1867
- // ...router.location,
1868
- const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
1869
-
1870
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
1871
-
1872
- const fromMatches = router.matchRoutes(router.location.pathname, {
1873
- strictParseParams: true
1874
- });
1875
- const toMatches = router.matchRoutes(pathname);
1876
-
1877
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
1878
-
1879
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1880
-
1881
- if (nextParams) {
1882
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
1883
- Object.assign({}, nextParams, fn(nextParams));
1884
- });
1885
- }
1886
-
1887
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
1888
-
1889
- 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
1890
-
1891
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1892
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
1893
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
1894
- : {}; // Then post filters
1895
-
1896
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1897
- const search = replaceEqualDeep(router.location.search, postFilteredSearch);
1898
- const searchStr = router.options.stringifySearch(search);
1899
- let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
1900
- hash = hash ? "#" + hash : '';
1901
- return {
1902
- pathname,
1903
- search,
1904
- searchStr,
1905
- state: router.location.state,
1906
- hash,
1907
- href: "" + pathname + searchStr + hash,
1908
- key: dest.key
1909
- };
1910
- },
1911
- commitLocation: (next, replace) => {
1912
- const id = '' + Date.now() + Math.random();
1913
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
1914
- let nextAction = 'replace';
1915
-
1916
- if (!replace) {
1917
- nextAction = 'push';
1918
- }
1919
-
1920
- const isSameUrl = router.parseLocation(history.location).href === next.href;
1921
-
1922
- if (isSameUrl && !next.key) {
1923
- nextAction = 'replace';
1924
- }
1925
-
1926
- if (nextAction === 'replace') {
1927
- history.replace({
1928
- pathname: next.pathname,
1929
- hash: next.hash,
1930
- search: next.searchStr
1931
- }, {
1932
- id
1933
- });
1934
- } else {
1935
- history.push({
1936
- pathname: next.pathname,
1937
- hash: next.hash,
1938
- search: next.searchStr
1939
- }, {
1940
- id
1941
- });
1942
- }
1943
-
1944
- router.navigationPromise = new Promise(resolve => {
1945
- const previousNavigationResolve = router.resolveNavigation;
1946
-
1947
- router.resolveNavigation = () => {
1948
- previousNavigationResolve();
1949
- resolve();
1950
- };
1951
- });
1952
- return router.navigationPromise;
1953
- },
1954
- buildNext: opts => {
1955
- const next = router.buildLocation(opts);
1956
- const matches = router.matchRoutes(next.pathname);
1957
-
1958
- const __preSearchFilters = matches.map(match => {
1959
- var _match$options$preSea;
1960
-
1961
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
1962
- }).flat().filter(Boolean);
1963
-
1964
- const __postSearchFilters = matches.map(match => {
1965
- var _match$options$postSe;
1966
-
1967
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
1968
- }).flat().filter(Boolean);
1969
-
1970
- return router.buildLocation(_extends({}, opts, {
1971
- __preSearchFilters,
1972
- __postSearchFilters
1973
- }));
1974
- },
1975
1862
  cancelMatches: () => {
1976
1863
  var _router$state$pending, _router$state$pending2;
1977
1864
  [...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 => {
@@ -2074,6 +1961,7 @@
2074
1961
  params: d.params,
2075
1962
  search: d.search
2076
1963
  });
1964
+ delete router.matchCache[d.matchId];
2077
1965
  });
2078
1966
 
2079
1967
  if (matches.some(d => d.status === 'loading')) {
@@ -2113,7 +2001,21 @@
2113
2001
  delete router.matchCache[matchId];
2114
2002
  });
2115
2003
  },
2116
- loadRoute: async function loadRoute(navigateOpts, loaderOpts) {
2004
+ loadRoute: async function loadRoute(navigateOpts) {
2005
+ if (navigateOpts === void 0) {
2006
+ navigateOpts = router.location;
2007
+ }
2008
+
2009
+ const next = router.buildNext(navigateOpts);
2010
+ const matches = router.matchRoutes(next.pathname, {
2011
+ strictParseParams: true
2012
+ });
2013
+ await router.loadMatches(matches);
2014
+ return matches;
2015
+ },
2016
+ preloadRoute: async function preloadRoute(navigateOpts, loaderOpts) {
2017
+ var _ref4, _ref5, _loaderOpts$maxAge, _ref6, _ref7, _loaderOpts$gcMaxAge;
2018
+
2117
2019
  if (navigateOpts === void 0) {
2118
2020
  navigateOpts = router.location;
2119
2021
  }
@@ -2124,7 +2026,8 @@
2124
2026
  });
2125
2027
  await router.loadMatches(matches, {
2126
2028
  preload: true,
2127
- maxAge: loaderOpts.maxAge
2029
+ maxAge: (_ref4 = (_ref5 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref5 : router.options.defaultLoaderMaxAge) != null ? _ref4 : 0,
2030
+ gcMaxAge: (_ref6 = (_ref7 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref7 : router.options.defaultLoaderGcMaxAge) != null ? _ref6 : 0
2128
2031
  });
2129
2032
  return matches;
2130
2033
  },
@@ -2218,33 +2121,11 @@
2218
2121
  return matches;
2219
2122
  },
2220
2123
  loadMatches: async (resolvedMatches, loaderOpts) => {
2221
- const now = Date.now();
2222
2124
  const matchPromises = resolvedMatches.map(async match => {
2223
2125
  // Validate the match (loads search params etc)
2224
- match.__.validate(); // // If the match doesn't have a loader, don't attempt to load it
2225
- // if (!match.hasLoaders()) {
2226
- // return
2227
- // }
2228
- // If this is a preload, add it to the preload cache
2229
-
2230
-
2231
- if (loaderOpts != null && loaderOpts.preload && (loaderOpts == null ? void 0 : loaderOpts.maxAge) > 0) {
2232
- // If the match is currently active, don't preload it
2233
- if (router.state.matches.find(d => d.matchId === match.matchId)) {
2234
- return;
2235
- }
2126
+ match.__.validate();
2236
2127
 
2237
- router.matchCache[match.matchId] = {
2238
- gc: now + loaderOpts.maxAge,
2239
- // TODO: Should this use the route's maxAge?
2240
- match
2241
- };
2242
- } // If the match is invalid, errored or idle, trigger it to load
2243
-
2244
-
2245
- if (match.status === 'success' && match.getIsInvalid() || match.status === 'error' || match.status === 'idle') {
2246
- match.load();
2247
- }
2128
+ match.load(loaderOpts);
2248
2129
 
2249
2130
  if (match.status === 'loading') {
2250
2131
  // If requested, start the pending timers
@@ -2268,7 +2149,7 @@
2268
2149
  }
2269
2150
  });
2270
2151
  },
2271
- reload: () => router._navigate({
2152
+ reload: () => router.__.navigate({
2272
2153
  fromCurrent: true,
2273
2154
  replace: true,
2274
2155
  search: true
@@ -2301,11 +2182,7 @@
2301
2182
  to: next.pathname
2302
2183
  }));
2303
2184
  },
2304
- _navigate: location => {
2305
- const next = router.buildNext(location);
2306
- return router.commitLocation(next, location.replace);
2307
- },
2308
- navigate: async _ref4 => {
2185
+ navigate: async _ref8 => {
2309
2186
  let {
2310
2187
  from,
2311
2188
  to = '.',
@@ -2313,7 +2190,7 @@
2313
2190
  hash,
2314
2191
  replace,
2315
2192
  params
2316
- } = _ref4;
2193
+ } = _ref8;
2317
2194
  // If this link simply reloads the current route,
2318
2195
  // make sure it has a new key so it will trigger a data refresh
2319
2196
  // If this `to` is a valid external URL, return
@@ -2328,7 +2205,7 @@
2328
2205
  } catch (e) {}
2329
2206
 
2330
2207
  invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2331
- return router._navigate({
2208
+ return router.__.navigate({
2332
2209
  from: fromString,
2333
2210
  to: toString,
2334
2211
  search,
@@ -2337,8 +2214,8 @@
2337
2214
  params
2338
2215
  });
2339
2216
  },
2340
- buildLink: _ref5 => {
2341
- var _preload, _ref6, _ref7, _ref8;
2217
+ buildLink: _ref9 => {
2218
+ var _preload, _ref10;
2342
2219
 
2343
2220
  let {
2344
2221
  from,
@@ -2351,9 +2228,10 @@
2351
2228
  activeOptions,
2352
2229
  preload,
2353
2230
  preloadMaxAge: userPreloadMaxAge,
2231
+ preloadGcMaxAge: userPreloadGcMaxAge,
2354
2232
  preloadDelay: userPreloadDelay,
2355
2233
  disabled
2356
- } = _ref5;
2234
+ } = _ref9;
2357
2235
 
2358
2236
  // If this link simply reloads the current route,
2359
2237
  // make sure it has a new key so it will trigger a data refresh
@@ -2376,9 +2254,8 @@
2376
2254
  replace
2377
2255
  };
2378
2256
  const next = router.buildNext(nextOpts);
2379
- preload = (_preload = preload) != null ? _preload : router.options.defaultLinkPreload;
2380
- const preloadMaxAge = (_ref6 = (_ref7 = userPreloadMaxAge != null ? userPreloadMaxAge : router.options.defaultLinkPreloadMaxAge) != null ? _ref7 : router.options.defaultLoaderGcMaxAge) != null ? _ref6 : 0;
2381
- const preloadDelay = (_ref8 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultLinkPreloadDelay) != null ? _ref8 : 0; // Compare path/hash for matches
2257
+ preload = (_preload = preload) != null ? _preload : router.options.defaultPreload;
2258
+ const preloadDelay = (_ref10 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultPreloadDelay) != null ? _ref10 : 0; // Compare path/hash for matches
2382
2259
 
2383
2260
  const pathIsEqual = router.state.location.pathname === next.pathname;
2384
2261
  const currentPathSplit = router.state.location.pathname.split('/');
@@ -2400,15 +2277,16 @@
2400
2277
  } // All is well? Navigate!)
2401
2278
 
2402
2279
 
2403
- router._navigate(nextOpts);
2280
+ router.__.navigate(nextOpts);
2404
2281
  }
2405
2282
  }; // The click handler
2406
2283
 
2407
2284
 
2408
2285
  const handleFocus = e => {
2409
- if (preload && preloadMaxAge > 0) {
2410
- router.loadRoute(nextOpts, {
2411
- maxAge: preloadMaxAge
2286
+ if (preload) {
2287
+ router.preloadRoute(nextOpts, {
2288
+ maxAge: userPreloadMaxAge,
2289
+ gcMaxAge: userPreloadGcMaxAge
2412
2290
  });
2413
2291
  }
2414
2292
  };
@@ -2416,15 +2294,16 @@
2416
2294
  const handleEnter = e => {
2417
2295
  const target = e.target || {};
2418
2296
 
2419
- if (preload && preloadMaxAge > 0) {
2297
+ if (preload) {
2420
2298
  if (target.preloadTimeout) {
2421
2299
  return;
2422
2300
  }
2423
2301
 
2424
2302
  target.preloadTimeout = setTimeout(() => {
2425
2303
  target.preloadTimeout = null;
2426
- router.loadRoute(nextOpts, {
2427
- maxAge: preloadMaxAge
2304
+ router.preloadRoute(nextOpts, {
2305
+ maxAge: userPreloadMaxAge,
2306
+ gcMaxAge: userPreloadGcMaxAge
2428
2307
  });
2429
2308
  }, preloadDelay);
2430
2309
  }
@@ -2449,9 +2328,174 @@
2449
2328
  isActive,
2450
2329
  disabled
2451
2330
  };
2331
+ },
2332
+ buildNext: opts => {
2333
+ const next = router.__.buildLocation(opts);
2334
+
2335
+ const matches = router.matchRoutes(next.pathname);
2336
+
2337
+ const __preSearchFilters = matches.map(match => {
2338
+ var _match$options$preSea;
2339
+
2340
+ return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
2341
+ }).flat().filter(Boolean);
2342
+
2343
+ const __postSearchFilters = matches.map(match => {
2344
+ var _match$options$postSe;
2345
+
2346
+ return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
2347
+ }).flat().filter(Boolean);
2348
+
2349
+ return router.__.buildLocation(_extends({}, opts, {
2350
+ __preSearchFilters,
2351
+ __postSearchFilters
2352
+ }));
2353
+ },
2354
+ __: {
2355
+ buildRouteTree: rootRouteConfig => {
2356
+ const recurseRoutes = (routeConfigs, parent) => {
2357
+ return routeConfigs.map(routeConfig => {
2358
+ const routeOptions = routeConfig.options;
2359
+ const route = createRoute(routeConfig, routeOptions, parent, router); // {
2360
+ // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
2361
+ // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
2362
+ // }
2363
+
2364
+ const existingRoute = router.routesById[route.routeId];
2365
+
2366
+ if (existingRoute) {
2367
+ {
2368
+ console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
2369
+ }
2370
+
2371
+ throw new Error();
2372
+ }
2373
+ router.routesById[route.routeId] = route;
2374
+ const children = routeConfig.children;
2375
+ route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
2376
+ return route;
2377
+ });
2378
+ };
2379
+
2380
+ const routes = recurseRoutes([rootRouteConfig]);
2381
+ return routes[0];
2382
+ },
2383
+ parseLocation: (location, previousLocation) => {
2384
+ var _location$hash$split$;
2385
+
2386
+ const parsedSearch = router.options.parseSearch(location.search);
2387
+ return {
2388
+ pathname: location.pathname,
2389
+ searchStr: location.search,
2390
+ search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
2391
+ hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
2392
+ href: "" + location.pathname + location.search + location.hash,
2393
+ state: location.state,
2394
+ key: location.key
2395
+ };
2396
+ },
2397
+ navigate: location => {
2398
+ const next = router.buildNext(location);
2399
+ return router.__.commitLocation(next, location.replace);
2400
+ },
2401
+ buildLocation: function buildLocation(dest) {
2402
+ var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
2403
+
2404
+ if (dest === void 0) {
2405
+ dest = {};
2406
+ }
2407
+
2408
+ // const resolvedFrom: Location = {
2409
+ // ...router.location,
2410
+ const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
2411
+
2412
+ let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
2413
+
2414
+ const fromMatches = router.matchRoutes(router.location.pathname, {
2415
+ strictParseParams: true
2416
+ });
2417
+ const toMatches = router.matchRoutes(pathname);
2418
+
2419
+ const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
2420
+
2421
+ let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
2422
+
2423
+ if (nextParams) {
2424
+ toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
2425
+ Object.assign({}, nextParams, fn(nextParams));
2426
+ });
2427
+ }
2428
+
2429
+ pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
2430
+
2431
+ 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
2432
+
2433
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
2434
+ : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
2435
+ : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
2436
+ : {}; // Then post filters
2437
+
2438
+ const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
2439
+ const search = replaceEqualDeep(router.location.search, postFilteredSearch);
2440
+ const searchStr = router.options.stringifySearch(search);
2441
+ let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
2442
+ hash = hash ? "#" + hash : '';
2443
+ return {
2444
+ pathname,
2445
+ search,
2446
+ searchStr,
2447
+ state: router.location.state,
2448
+ hash,
2449
+ href: "" + pathname + searchStr + hash,
2450
+ key: dest.key
2451
+ };
2452
+ },
2453
+ commitLocation: (next, replace) => {
2454
+ const id = '' + Date.now() + Math.random();
2455
+ if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
2456
+ let nextAction = 'replace';
2457
+
2458
+ if (!replace) {
2459
+ nextAction = 'push';
2460
+ }
2461
+
2462
+ const isSameUrl = router.__.parseLocation(history.location).href === next.href;
2463
+
2464
+ if (isSameUrl && !next.key) {
2465
+ nextAction = 'replace';
2466
+ }
2467
+
2468
+ if (nextAction === 'replace') {
2469
+ history.replace({
2470
+ pathname: next.pathname,
2471
+ hash: next.hash,
2472
+ search: next.searchStr
2473
+ }, {
2474
+ id
2475
+ });
2476
+ } else {
2477
+ history.push({
2478
+ pathname: next.pathname,
2479
+ hash: next.hash,
2480
+ search: next.searchStr
2481
+ }, {
2482
+ id
2483
+ });
2484
+ }
2485
+
2486
+ router.navigationPromise = new Promise(resolve => {
2487
+ const previousNavigationResolve = router.resolveNavigation;
2488
+
2489
+ router.resolveNavigation = () => {
2490
+ previousNavigationResolve();
2491
+ resolve();
2492
+ };
2493
+ });
2494
+ return router.navigationPromise;
2495
+ }
2452
2496
  }
2453
2497
  };
2454
- router.location = router.parseLocation(history.location);
2498
+ router.location = router.__.parseLocation(history.location);
2455
2499
  router.state.location = router.location;
2456
2500
  router.update(userOptions); // Allow frameworks to hook into the router creation
2457
2501
 
@@ -2483,6 +2527,17 @@
2483
2527
  function createReactRouter(opts) {
2484
2528
  const makeRouteExt = (route, router) => {
2485
2529
  return {
2530
+ useRoute: function useRoute(subRouteId) {
2531
+ if (subRouteId === void 0) {
2532
+ subRouteId = '.';
2533
+ }
2534
+
2535
+ const resolvedRouteId = router.resolvePath(route.routeId, subRouteId);
2536
+ const resolvedRoute = router.getRoute(resolvedRouteId);
2537
+ useRouterSubscription(router);
2538
+ invariant(resolvedRoute, "Could not find a route for route \"" + resolvedRouteId + "\"! Did you forget to add it to your route config?");
2539
+ return resolvedRoute;
2540
+ },
2486
2541
  linkProps: options => {
2487
2542
  var _functionalUpdate, _functionalUpdate2;
2488
2543
 
@@ -2590,12 +2645,6 @@
2590
2645
  useRouterSubscription(router);
2591
2646
  return router.state;
2592
2647
  },
2593
- useRoute: routeId => {
2594
- const route = router.getRoute(routeId);
2595
- useRouterSubscription(router);
2596
- invariant(route, "Could not find a route for route \"" + routeId + "\"! Did you forget to add it to your route config?");
2597
- return route;
2598
- },
2599
2648
  useMatch: routeId => {
2600
2649
  useRouterSubscription(router);
2601
2650
  invariant(routeId !== rootRouteId, "\"" + rootRouteId + "\" cannot be used with useMatch! Did you mean to useRoute(\"" + rootRouteId + "\")?");
@@ -2623,6 +2672,19 @@
2623
2672
  } = _ref;
2624
2673
  const routeExt = makeRouteExt(route, router);
2625
2674
  Object.assign(route, routeExt);
2675
+ },
2676
+ createElement: async element => {
2677
+ if (typeof element === 'function') {
2678
+ const res = await element(); // Support direct import() calls
2679
+
2680
+ if (typeof res === 'object' && res.default) {
2681
+ return /*#__PURE__*/React__namespace.createElement(res.default);
2682
+ } else {
2683
+ return res;
2684
+ }
2685
+ }
2686
+
2687
+ return element;
2626
2688
  }
2627
2689
  }));
2628
2690
  return coreRouter;
@@ -2807,11 +2869,36 @@
2807
2869
  opacity: 0.5
2808
2870
  }
2809
2871
  }, "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."));
2810
- } // TODO: Add prompt
2872
+ }
2873
+ function usePrompt(message, when) {
2874
+ const router = useRouter();
2875
+ React__namespace.useEffect(() => {
2876
+ if (!when) return;
2877
+ let unblock = router.history.block(transition => {
2878
+ if (window.confirm(message)) {
2879
+ unblock();
2880
+ transition.retry();
2881
+ } else {
2882
+ router.location.pathname = window.location.pathname;
2883
+ }
2884
+ });
2885
+ return unblock;
2886
+ }, [when, location, message]);
2887
+ }
2888
+ function Prompt(_ref6) {
2889
+ let {
2890
+ message,
2891
+ when,
2892
+ children
2893
+ } = _ref6;
2894
+ usePrompt(message, when != null ? when : true);
2895
+ return children != null ? children : null;
2896
+ }
2811
2897
 
2812
2898
  exports.DefaultErrorBoundary = DefaultErrorBoundary;
2813
2899
  exports.MatchesProvider = MatchesProvider;
2814
2900
  exports.Outlet = Outlet;
2901
+ exports.Prompt = Prompt;
2815
2902
  exports.RouterProvider = RouterProvider;
2816
2903
  exports.cascadeLoaderData = cascadeLoaderData;
2817
2904
  exports.cleanPath = cleanPath;
@@ -2843,6 +2930,7 @@
2843
2930
  exports.trimPath = trimPath;
2844
2931
  exports.trimPathLeft = trimPathLeft;
2845
2932
  exports.trimPathRight = trimPathRight;
2933
+ exports.usePrompt = usePrompt;
2846
2934
  exports.warning = warning;
2847
2935
 
2848
2936
  Object.defineProperty(exports, '__esModule', { value: true });