@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.
@@ -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
@@ -1518,9 +1553,33 @@
1518
1553
  routeMatch.isInvalid = true;
1519
1554
  },
1520
1555
  hasLoaders: () => {
1521
- 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'));
1557
+ },
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
+ }
1522
1581
  },
1523
- load: async opts => {
1582
+ fetch: async opts => {
1524
1583
  const id = '' + Date.now() + Math.random();
1525
1584
  routeMatch.__.latestId = id; // If the match was in an error state, set it
1526
1585
  // to a loading state again. Otherwise, keep it
@@ -1539,21 +1598,7 @@
1539
1598
  routeMatch.__.resolve = resolve;
1540
1599
 
1541
1600
  const loaderPromise = (async () => {
1542
- const importer = routeMatch.options.import; // First, run any importers
1543
-
1544
- if (importer) {
1545
- routeMatch.__.importPromise = importer({
1546
- params: routeMatch.params // search: routeMatch.search,
1547
-
1548
- }).then(imported => {
1549
- routeMatch.__ = _extends({}, routeMatch.__, imported);
1550
- });
1551
- } // Wait for the importer to finish before
1552
- // attempting to load elements and data
1553
-
1554
-
1555
- await routeMatch.__.importPromise; // Next, load the elements and data in parallel
1556
-
1601
+ // Load the elements and data in parallel
1557
1602
  routeMatch.__.elementsPromise = (async () => {
1558
1603
  // then run all element and data loaders in parallel
1559
1604
  // For each element type, potentially load it asynchronously
@@ -1564,12 +1609,7 @@
1564
1609
  return;
1565
1610
  }
1566
1611
 
1567
- if (typeof routeElement === 'function') {
1568
- const res = await routeElement(routeMatch);
1569
- routeMatch.__[type] = res;
1570
- } else {
1571
- routeMatch.__[type] = routeMatch.options[type];
1572
- }
1612
+ routeMatch.__[type] = await router.options.createElement(routeElement);
1573
1613
  }));
1574
1614
  })();
1575
1615
 
@@ -1725,6 +1765,7 @@
1725
1765
  });
1726
1766
 
1727
1767
  let router = {
1768
+ history,
1728
1769
  options: originalOptions,
1729
1770
  listeners: [],
1730
1771
  removeActionQueue: [],
@@ -1743,6 +1784,7 @@
1743
1784
  location: null,
1744
1785
  matches: [],
1745
1786
  actions: {},
1787
+ loaders: {},
1746
1788
  loaderData: {},
1747
1789
  lastUpdated: Date.now(),
1748
1790
  isFetching: false,
@@ -1764,24 +1806,25 @@
1764
1806
  isPreloading: Object.values(router.matchCache).some(d => d.match.isFetching && !router.state.matches.find(dd => dd.matchId === d.match.matchId))
1765
1807
  });
1766
1808
  cascadeLoaderData(router.state.matches);
1767
- router.listeners.forEach(listener => listener());
1809
+ router.listeners.forEach(listener => listener(router));
1768
1810
  },
1769
1811
  mount: () => {
1770
- const next = router.buildLocation({
1812
+ const next = router.__.buildLocation({
1771
1813
  to: '.',
1772
1814
  search: true,
1773
1815
  hash: true
1774
1816
  }); // If the current location isn't updated, trigger a navigation
1775
1817
  // to the current location. Otherwise, load the current location.
1776
1818
 
1819
+
1777
1820
  if (next.href !== router.location.href) {
1778
- router.commitLocation(next, true);
1821
+ router.__.commitLocation(next, true);
1779
1822
  } else {
1780
1823
  router.loadLocation();
1781
1824
  }
1782
1825
 
1783
1826
  const unsub = history.listen(event => {
1784
- router.loadLocation(router.parseLocation(event.location, router.location));
1827
+ router.loadLocation(router.__.parseLocation(event.location, router.location));
1785
1828
  }); // addEventListener does not exist in React Native, but window does
1786
1829
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1787
1830
 
@@ -1811,169 +1854,11 @@
1811
1854
 
1812
1855
  if (routeConfig) {
1813
1856
  router.routesById = {};
1814
- router.routeTree = router.buildRouteTree(routeConfig);
1857
+ router.routeTree = router.__.buildRouteTree(routeConfig);
1815
1858
  }
1816
1859
 
1817
1860
  return router;
1818
1861
  },
1819
- buildRouteTree: rootRouteConfig => {
1820
- const recurseRoutes = (routeConfigs, parent) => {
1821
- return routeConfigs.map(routeConfig => {
1822
- const routeOptions = routeConfig.options;
1823
- const route = createRoute(routeConfig, routeOptions, parent, router); // {
1824
- // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
1825
- // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
1826
- // }
1827
-
1828
- const existingRoute = router.routesById[route.routeId];
1829
-
1830
- if (existingRoute) {
1831
- {
1832
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
1833
- }
1834
-
1835
- throw new Error();
1836
- }
1837
- router.routesById[route.routeId] = route;
1838
- const children = routeConfig.children;
1839
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
1840
- return route;
1841
- });
1842
- };
1843
-
1844
- const routes = recurseRoutes([rootRouteConfig]);
1845
- return routes[0];
1846
- },
1847
- parseLocation: (location, previousLocation) => {
1848
- var _location$hash$split$;
1849
-
1850
- const parsedSearch = router.options.parseSearch(location.search);
1851
- return {
1852
- pathname: location.pathname,
1853
- searchStr: location.search,
1854
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
1855
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
1856
- href: "" + location.pathname + location.search + location.hash,
1857
- state: location.state,
1858
- key: location.key
1859
- };
1860
- },
1861
- buildLocation: function buildLocation(dest) {
1862
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
1863
-
1864
- if (dest === void 0) {
1865
- dest = {};
1866
- }
1867
-
1868
- // const resolvedFrom: Location = {
1869
- // ...router.location,
1870
- const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
1871
-
1872
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
1873
-
1874
- const fromMatches = router.matchRoutes(router.location.pathname, {
1875
- strictParseParams: true
1876
- });
1877
- const toMatches = router.matchRoutes(pathname);
1878
-
1879
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
1880
-
1881
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1882
-
1883
- if (nextParams) {
1884
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
1885
- Object.assign({}, nextParams, fn(nextParams));
1886
- });
1887
- }
1888
-
1889
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
1890
-
1891
- 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
1892
-
1893
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1894
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
1895
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
1896
- : {}; // Then post filters
1897
-
1898
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1899
- const search = replaceEqualDeep(router.location.search, postFilteredSearch);
1900
- const searchStr = router.options.stringifySearch(search);
1901
- let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
1902
- hash = hash ? "#" + hash : '';
1903
- return {
1904
- pathname,
1905
- search,
1906
- searchStr,
1907
- state: router.location.state,
1908
- hash,
1909
- href: "" + pathname + searchStr + hash,
1910
- key: dest.key
1911
- };
1912
- },
1913
- commitLocation: (next, replace) => {
1914
- const id = '' + Date.now() + Math.random();
1915
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
1916
- let nextAction = 'replace';
1917
-
1918
- if (!replace) {
1919
- nextAction = 'push';
1920
- }
1921
-
1922
- const isSameUrl = router.parseLocation(history.location).href === next.href;
1923
-
1924
- if (isSameUrl && !next.key) {
1925
- nextAction = 'replace';
1926
- }
1927
-
1928
- if (nextAction === 'replace') {
1929
- history.replace({
1930
- pathname: next.pathname,
1931
- hash: next.hash,
1932
- search: next.searchStr
1933
- }, {
1934
- id
1935
- });
1936
- } else {
1937
- history.push({
1938
- pathname: next.pathname,
1939
- hash: next.hash,
1940
- search: next.searchStr
1941
- }, {
1942
- id
1943
- });
1944
- }
1945
-
1946
- router.navigationPromise = new Promise(resolve => {
1947
- const previousNavigationResolve = router.resolveNavigation;
1948
-
1949
- router.resolveNavigation = () => {
1950
- previousNavigationResolve();
1951
- resolve();
1952
- };
1953
- });
1954
- return router.navigationPromise;
1955
- },
1956
- buildNext: opts => {
1957
- const next = router.buildLocation(opts);
1958
- const matches = router.matchRoutes(next.pathname);
1959
-
1960
- const __preSearchFilters = matches.map(match => {
1961
- var _match$options$preSea;
1962
-
1963
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
1964
- }).flat().filter(Boolean);
1965
-
1966
- const __postSearchFilters = matches.map(match => {
1967
- var _match$options$postSe;
1968
-
1969
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
1970
- }).flat().filter(Boolean);
1971
-
1972
- return router.buildLocation(_extends({}, opts, {
1973
- __preSearchFilters,
1974
- __postSearchFilters
1975
- }));
1976
- },
1977
1862
  cancelMatches: () => {
1978
1863
  var _router$state$pending, _router$state$pending2;
1979
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 => {
@@ -2076,6 +1961,7 @@
2076
1961
  params: d.params,
2077
1962
  search: d.search
2078
1963
  });
1964
+ delete router.matchCache[d.matchId];
2079
1965
  });
2080
1966
 
2081
1967
  if (matches.some(d => d.status === 'loading')) {
@@ -2235,32 +2121,11 @@
2235
2121
  return matches;
2236
2122
  },
2237
2123
  loadMatches: async (resolvedMatches, loaderOpts) => {
2238
- const now = Date.now();
2239
- const minMaxAge = loaderOpts != null && loaderOpts.preload ? Math.max(loaderOpts == null ? void 0 : loaderOpts.maxAge, loaderOpts == null ? void 0 : loaderOpts.gcMaxAge) : 0;
2240
2124
  const matchPromises = resolvedMatches.map(async match => {
2241
2125
  // Validate the match (loads search params etc)
2242
- match.__.validate(); // If this is a preload, add it to the preload cache
2126
+ match.__.validate();
2243
2127
 
2244
-
2245
- if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
2246
- // If the match is currently active, don't preload it
2247
- if (router.state.matches.find(d => d.matchId === match.matchId)) {
2248
- return;
2249
- }
2250
-
2251
- router.matchCache[match.matchId] = {
2252
- gc: now + loaderOpts.gcMaxAge,
2253
- match
2254
- };
2255
- } // If the match is invalid, errored or idle, trigger it to load
2256
-
2257
-
2258
- if (match.status === 'success' && match.getIsInvalid() || match.status === 'error' || match.status === 'idle') {
2259
- const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
2260
- match.load({
2261
- maxAge
2262
- });
2263
- }
2128
+ match.load(loaderOpts);
2264
2129
 
2265
2130
  if (match.status === 'loading') {
2266
2131
  // If requested, start the pending timers
@@ -2284,7 +2149,7 @@
2284
2149
  }
2285
2150
  });
2286
2151
  },
2287
- reload: () => router._navigate({
2152
+ reload: () => router.__.navigate({
2288
2153
  fromCurrent: true,
2289
2154
  replace: true,
2290
2155
  search: true
@@ -2317,10 +2182,6 @@
2317
2182
  to: next.pathname
2318
2183
  }));
2319
2184
  },
2320
- _navigate: location => {
2321
- const next = router.buildNext(location);
2322
- return router.commitLocation(next, location.replace);
2323
- },
2324
2185
  navigate: async _ref8 => {
2325
2186
  let {
2326
2187
  from,
@@ -2344,7 +2205,7 @@
2344
2205
  } catch (e) {}
2345
2206
 
2346
2207
  invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2347
- return router._navigate({
2208
+ return router.__.navigate({
2348
2209
  from: fromString,
2349
2210
  to: toString,
2350
2211
  search,
@@ -2416,7 +2277,7 @@
2416
2277
  } // All is well? Navigate!)
2417
2278
 
2418
2279
 
2419
- router._navigate(nextOpts);
2280
+ router.__.navigate(nextOpts);
2420
2281
  }
2421
2282
  }; // The click handler
2422
2283
 
@@ -2467,9 +2328,174 @@
2467
2328
  isActive,
2468
2329
  disabled
2469
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
+ }
2470
2496
  }
2471
2497
  };
2472
- router.location = router.parseLocation(history.location);
2498
+ router.location = router.__.parseLocation(history.location);
2473
2499
  router.state.location = router.location;
2474
2500
  router.update(userOptions); // Allow frameworks to hook into the router creation
2475
2501
 
@@ -2495,12 +2521,23 @@
2495
2521
  }
2496
2522
 
2497
2523
  const useRouterSubscription = router => {
2498
- shim.useSyncExternalStore(cb => router.subscribe(() => cb()), () => router.state);
2524
+ shim.useSyncExternalStore(cb => router.subscribe(() => cb()), () => router.state, () => router.state);
2499
2525
  };
2500
2526
 
2501
2527
  function createReactRouter(opts) {
2502
2528
  const makeRouteExt = (route, router) => {
2503
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
+ },
2504
2541
  linkProps: options => {
2505
2542
  var _functionalUpdate, _functionalUpdate2;
2506
2543
 
@@ -2608,12 +2645,6 @@
2608
2645
  useRouterSubscription(router);
2609
2646
  return router.state;
2610
2647
  },
2611
- useRoute: routeId => {
2612
- const route = router.getRoute(routeId);
2613
- useRouterSubscription(router);
2614
- invariant(route, "Could not find a route for route \"" + routeId + "\"! Did you forget to add it to your route config?");
2615
- return route;
2616
- },
2617
2648
  useMatch: routeId => {
2618
2649
  useRouterSubscription(router);
2619
2650
  invariant(routeId !== rootRouteId, "\"" + rootRouteId + "\" cannot be used with useMatch! Did you mean to useRoute(\"" + rootRouteId + "\")?");
@@ -2641,6 +2672,19 @@
2641
2672
  } = _ref;
2642
2673
  const routeExt = makeRouteExt(route, router);
2643
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;
2644
2688
  }
2645
2689
  }));
2646
2690
  return coreRouter;
@@ -2825,11 +2869,36 @@
2825
2869
  opacity: 0.5
2826
2870
  }
2827
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."));
2828
- } // 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
+ }
2829
2897
 
2830
2898
  exports.DefaultErrorBoundary = DefaultErrorBoundary;
2831
2899
  exports.MatchesProvider = MatchesProvider;
2832
2900
  exports.Outlet = Outlet;
2901
+ exports.Prompt = Prompt;
2833
2902
  exports.RouterProvider = RouterProvider;
2834
2903
  exports.cascadeLoaderData = cascadeLoaderData;
2835
2904
  exports.cleanPath = cleanPath;
@@ -2861,6 +2930,7 @@
2861
2930
  exports.trimPath = trimPath;
2862
2931
  exports.trimPathLeft = trimPathLeft;
2863
2932
  exports.trimPathRight = trimPathRight;
2933
+ exports.usePrompt = usePrompt;
2864
2934
  exports.warning = warning;
2865
2935
 
2866
2936
  Object.defineProperty(exports, '__esModule', { value: true });