@tanstack/react-router 0.0.1-alpha.9 → 0.0.1-beta.2

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
@@ -1502,9 +1537,33 @@ function createRouteMatch(router, route, opts) {
1502
1537
  routeMatch.isInvalid = true;
1503
1538
  },
1504
1539
  hasLoaders: () => {
1505
- 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'));
1541
+ },
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
+ }
1506
1565
  },
1507
- load: async opts => {
1566
+ fetch: async opts => {
1508
1567
  const id = '' + Date.now() + Math.random();
1509
1568
  routeMatch.__.latestId = id; // If the match was in an error state, set it
1510
1569
  // to a loading state again. Otherwise, keep it
@@ -1523,21 +1582,7 @@ function createRouteMatch(router, route, opts) {
1523
1582
  routeMatch.__.resolve = resolve;
1524
1583
 
1525
1584
  const loaderPromise = (async () => {
1526
- const importer = routeMatch.options.import; // First, run any importers
1527
-
1528
- if (importer) {
1529
- routeMatch.__.importPromise = importer({
1530
- params: routeMatch.params // search: routeMatch.search,
1531
-
1532
- }).then(imported => {
1533
- routeMatch.__ = _extends({}, routeMatch.__, imported);
1534
- });
1535
- } // Wait for the importer to finish before
1536
- // attempting to load elements and data
1537
-
1538
-
1539
- await routeMatch.__.importPromise; // Next, load the elements and data in parallel
1540
-
1585
+ // Load the elements and data in parallel
1541
1586
  routeMatch.__.elementsPromise = (async () => {
1542
1587
  // then run all element and data loaders in parallel
1543
1588
  // For each element type, potentially load it asynchronously
@@ -1548,12 +1593,7 @@ function createRouteMatch(router, route, opts) {
1548
1593
  return;
1549
1594
  }
1550
1595
 
1551
- if (typeof routeElement === 'function') {
1552
- const res = await routeElement(routeMatch);
1553
- routeMatch.__[type] = res;
1554
- } else {
1555
- routeMatch.__[type] = routeMatch.options[type];
1556
- }
1596
+ routeMatch.__[type] = await router.options.createElement(routeElement);
1557
1597
  }));
1558
1598
  })();
1559
1599
 
@@ -1709,6 +1749,7 @@ function createRouter(userOptions) {
1709
1749
  });
1710
1750
 
1711
1751
  let router = {
1752
+ history,
1712
1753
  options: originalOptions,
1713
1754
  listeners: [],
1714
1755
  removeActionQueue: [],
@@ -1727,6 +1768,7 @@ function createRouter(userOptions) {
1727
1768
  location: null,
1728
1769
  matches: [],
1729
1770
  actions: {},
1771
+ loaders: {},
1730
1772
  loaderData: {},
1731
1773
  lastUpdated: Date.now(),
1732
1774
  isFetching: false,
@@ -1748,24 +1790,25 @@ function createRouter(userOptions) {
1748
1790
  isPreloading: Object.values(router.matchCache).some(d => d.match.isFetching && !router.state.matches.find(dd => dd.matchId === d.match.matchId))
1749
1791
  });
1750
1792
  cascadeLoaderData(router.state.matches);
1751
- router.listeners.forEach(listener => listener());
1793
+ router.listeners.forEach(listener => listener(router));
1752
1794
  },
1753
1795
  mount: () => {
1754
- const next = router.buildLocation({
1796
+ const next = router.__.buildLocation({
1755
1797
  to: '.',
1756
1798
  search: true,
1757
1799
  hash: true
1758
1800
  }); // If the current location isn't updated, trigger a navigation
1759
1801
  // to the current location. Otherwise, load the current location.
1760
1802
 
1803
+
1761
1804
  if (next.href !== router.location.href) {
1762
- router.commitLocation(next, true);
1805
+ router.__.commitLocation(next, true);
1763
1806
  } else {
1764
1807
  router.loadLocation();
1765
1808
  }
1766
1809
 
1767
1810
  const unsub = history.listen(event => {
1768
- router.loadLocation(router.parseLocation(event.location, router.location));
1811
+ router.loadLocation(router.__.parseLocation(event.location, router.location));
1769
1812
  }); // addEventListener does not exist in React Native, but window does
1770
1813
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1771
1814
 
@@ -1795,169 +1838,11 @@ function createRouter(userOptions) {
1795
1838
 
1796
1839
  if (routeConfig) {
1797
1840
  router.routesById = {};
1798
- router.routeTree = router.buildRouteTree(routeConfig);
1841
+ router.routeTree = router.__.buildRouteTree(routeConfig);
1799
1842
  }
1800
1843
 
1801
1844
  return router;
1802
1845
  },
1803
- buildRouteTree: rootRouteConfig => {
1804
- const recurseRoutes = (routeConfigs, parent) => {
1805
- return routeConfigs.map(routeConfig => {
1806
- const routeOptions = routeConfig.options;
1807
- const route = createRoute(routeConfig, routeOptions, parent, router); // {
1808
- // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
1809
- // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
1810
- // }
1811
-
1812
- const existingRoute = router.routesById[route.routeId];
1813
-
1814
- if (existingRoute) {
1815
- if (process.env.NODE_ENV !== 'production') {
1816
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
1817
- }
1818
-
1819
- throw new Error();
1820
- }
1821
- router.routesById[route.routeId] = route;
1822
- const children = routeConfig.children;
1823
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
1824
- return route;
1825
- });
1826
- };
1827
-
1828
- const routes = recurseRoutes([rootRouteConfig]);
1829
- return routes[0];
1830
- },
1831
- parseLocation: (location, previousLocation) => {
1832
- var _location$hash$split$;
1833
-
1834
- const parsedSearch = router.options.parseSearch(location.search);
1835
- return {
1836
- pathname: location.pathname,
1837
- searchStr: location.search,
1838
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
1839
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
1840
- href: "" + location.pathname + location.search + location.hash,
1841
- state: location.state,
1842
- key: location.key
1843
- };
1844
- },
1845
- buildLocation: function buildLocation(dest) {
1846
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
1847
-
1848
- if (dest === void 0) {
1849
- dest = {};
1850
- }
1851
-
1852
- // const resolvedFrom: Location = {
1853
- // ...router.location,
1854
- const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
1855
-
1856
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
1857
-
1858
- const fromMatches = router.matchRoutes(router.location.pathname, {
1859
- strictParseParams: true
1860
- });
1861
- const toMatches = router.matchRoutes(pathname);
1862
-
1863
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
1864
-
1865
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1866
-
1867
- if (nextParams) {
1868
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
1869
- Object.assign({}, nextParams, fn(nextParams));
1870
- });
1871
- }
1872
-
1873
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
1874
-
1875
- 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
1876
-
1877
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1878
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
1879
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
1880
- : {}; // Then post filters
1881
-
1882
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1883
- const search = replaceEqualDeep(router.location.search, postFilteredSearch);
1884
- const searchStr = router.options.stringifySearch(search);
1885
- let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
1886
- hash = hash ? "#" + hash : '';
1887
- return {
1888
- pathname,
1889
- search,
1890
- searchStr,
1891
- state: router.location.state,
1892
- hash,
1893
- href: "" + pathname + searchStr + hash,
1894
- key: dest.key
1895
- };
1896
- },
1897
- commitLocation: (next, replace) => {
1898
- const id = '' + Date.now() + Math.random();
1899
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
1900
- let nextAction = 'replace';
1901
-
1902
- if (!replace) {
1903
- nextAction = 'push';
1904
- }
1905
-
1906
- const isSameUrl = router.parseLocation(history.location).href === next.href;
1907
-
1908
- if (isSameUrl && !next.key) {
1909
- nextAction = 'replace';
1910
- }
1911
-
1912
- if (nextAction === 'replace') {
1913
- history.replace({
1914
- pathname: next.pathname,
1915
- hash: next.hash,
1916
- search: next.searchStr
1917
- }, {
1918
- id
1919
- });
1920
- } else {
1921
- history.push({
1922
- pathname: next.pathname,
1923
- hash: next.hash,
1924
- search: next.searchStr
1925
- }, {
1926
- id
1927
- });
1928
- }
1929
-
1930
- router.navigationPromise = new Promise(resolve => {
1931
- const previousNavigationResolve = router.resolveNavigation;
1932
-
1933
- router.resolveNavigation = () => {
1934
- previousNavigationResolve();
1935
- resolve();
1936
- };
1937
- });
1938
- return router.navigationPromise;
1939
- },
1940
- buildNext: opts => {
1941
- const next = router.buildLocation(opts);
1942
- const matches = router.matchRoutes(next.pathname);
1943
-
1944
- const __preSearchFilters = matches.map(match => {
1945
- var _match$options$preSea;
1946
-
1947
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
1948
- }).flat().filter(Boolean);
1949
-
1950
- const __postSearchFilters = matches.map(match => {
1951
- var _match$options$postSe;
1952
-
1953
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
1954
- }).flat().filter(Boolean);
1955
-
1956
- return router.buildLocation(_extends({}, opts, {
1957
- __preSearchFilters,
1958
- __postSearchFilters
1959
- }));
1960
- },
1961
1846
  cancelMatches: () => {
1962
1847
  var _router$state$pending, _router$state$pending2;
1963
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 => {
@@ -2060,6 +1945,7 @@ function createRouter(userOptions) {
2060
1945
  params: d.params,
2061
1946
  search: d.search
2062
1947
  });
1948
+ delete router.matchCache[d.matchId];
2063
1949
  });
2064
1950
 
2065
1951
  if (matches.some(d => d.status === 'loading')) {
@@ -2219,32 +2105,11 @@ function createRouter(userOptions) {
2219
2105
  return matches;
2220
2106
  },
2221
2107
  loadMatches: async (resolvedMatches, loaderOpts) => {
2222
- const now = Date.now();
2223
- const minMaxAge = loaderOpts != null && loaderOpts.preload ? Math.max(loaderOpts == null ? void 0 : loaderOpts.maxAge, loaderOpts == null ? void 0 : loaderOpts.gcMaxAge) : 0;
2224
2108
  const matchPromises = resolvedMatches.map(async match => {
2225
2109
  // Validate the match (loads search params etc)
2226
- match.__.validate(); // If this is a preload, add it to the preload cache
2110
+ match.__.validate();
2227
2111
 
2228
-
2229
- if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
2230
- // If the match is currently active, don't preload it
2231
- if (router.state.matches.find(d => d.matchId === match.matchId)) {
2232
- return;
2233
- }
2234
-
2235
- router.matchCache[match.matchId] = {
2236
- gc: now + loaderOpts.gcMaxAge,
2237
- match
2238
- };
2239
- } // If the match is invalid, errored or idle, trigger it to load
2240
-
2241
-
2242
- if (match.status === 'success' && match.getIsInvalid() || match.status === 'error' || match.status === 'idle') {
2243
- const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
2244
- match.load({
2245
- maxAge
2246
- });
2247
- }
2112
+ match.load(loaderOpts);
2248
2113
 
2249
2114
  if (match.status === 'loading') {
2250
2115
  // If requested, start the pending timers
@@ -2268,7 +2133,7 @@ function createRouter(userOptions) {
2268
2133
  }
2269
2134
  });
2270
2135
  },
2271
- reload: () => router._navigate({
2136
+ reload: () => router.__.navigate({
2272
2137
  fromCurrent: true,
2273
2138
  replace: true,
2274
2139
  search: true
@@ -2301,10 +2166,6 @@ function createRouter(userOptions) {
2301
2166
  to: next.pathname
2302
2167
  }));
2303
2168
  },
2304
- _navigate: location => {
2305
- const next = router.buildNext(location);
2306
- return router.commitLocation(next, location.replace);
2307
- },
2308
2169
  navigate: async _ref8 => {
2309
2170
  let {
2310
2171
  from,
@@ -2328,7 +2189,7 @@ function createRouter(userOptions) {
2328
2189
  } catch (e) {}
2329
2190
 
2330
2191
  invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2331
- return router._navigate({
2192
+ return router.__.navigate({
2332
2193
  from: fromString,
2333
2194
  to: toString,
2334
2195
  search,
@@ -2400,7 +2261,7 @@ function createRouter(userOptions) {
2400
2261
  } // All is well? Navigate!)
2401
2262
 
2402
2263
 
2403
- router._navigate(nextOpts);
2264
+ router.__.navigate(nextOpts);
2404
2265
  }
2405
2266
  }; // The click handler
2406
2267
 
@@ -2451,9 +2312,174 @@ function createRouter(userOptions) {
2451
2312
  isActive,
2452
2313
  disabled
2453
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
+ }
2454
2480
  }
2455
2481
  };
2456
- router.location = router.parseLocation(history.location);
2482
+ router.location = router.__.parseLocation(history.location);
2457
2483
  router.state.location = router.location;
2458
2484
  router.update(userOptions); // Allow frameworks to hook into the router creation
2459
2485
 
@@ -2479,12 +2505,23 @@ function MatchesProvider(props) {
2479
2505
  }
2480
2506
 
2481
2507
  const useRouterSubscription = router => {
2482
- useSyncExternalStore(cb => router.subscribe(() => cb()), () => router.state);
2508
+ useSyncExternalStore(cb => router.subscribe(() => cb()), () => router.state, () => router.state);
2483
2509
  };
2484
2510
 
2485
2511
  function createReactRouter(opts) {
2486
2512
  const makeRouteExt = (route, router) => {
2487
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
+ },
2488
2525
  linkProps: options => {
2489
2526
  var _functionalUpdate, _functionalUpdate2;
2490
2527
 
@@ -2592,12 +2629,6 @@ function createReactRouter(opts) {
2592
2629
  useRouterSubscription(router);
2593
2630
  return router.state;
2594
2631
  },
2595
- useRoute: routeId => {
2596
- const route = router.getRoute(routeId);
2597
- useRouterSubscription(router);
2598
- invariant(route, "Could not find a route for route \"" + routeId + "\"! Did you forget to add it to your route config?");
2599
- return route;
2600
- },
2601
2632
  useMatch: routeId => {
2602
2633
  useRouterSubscription(router);
2603
2634
  invariant(routeId !== rootRouteId, "\"" + rootRouteId + "\" cannot be used with useMatch! Did you mean to useRoute(\"" + rootRouteId + "\")?");
@@ -2625,6 +2656,19 @@ function createReactRouter(opts) {
2625
2656
  } = _ref;
2626
2657
  const routeExt = makeRouteExt(route, router);
2627
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;
2628
2672
  }
2629
2673
  }));
2630
2674
  return coreRouter;
@@ -2809,7 +2853,31 @@ function DefaultErrorBoundary(_ref5) {
2809
2853
  opacity: 0.5
2810
2854
  }
2811
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."));
2812
- } // 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
+ }
2813
2881
 
2814
- 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 };
2815
2883
  //# sourceMappingURL=index.js.map