@tanstack/router-core 0.0.1-alpha.9 → 0.0.1-beta.10

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.
@@ -930,6 +930,12 @@
930
930
 
931
931
  return updater;
932
932
  }
933
+ function pick(parent, keys) {
934
+ return keys.reduce((obj, key) => {
935
+ obj[key] = parent[key];
936
+ return obj;
937
+ }, {});
938
+ }
933
939
 
934
940
  function joinPaths(paths) {
935
941
  return cleanPath(paths.filter(Boolean).join('/'));
@@ -1156,6 +1162,7 @@
1156
1162
  var str = decodeURIComponent(mix);
1157
1163
  if (str === 'false') return false;
1158
1164
  if (str === 'true') return true;
1165
+ if (str.charAt(0) === '0') return str;
1159
1166
  return +str * 0 === 0 ? +str : str;
1160
1167
  }
1161
1168
 
@@ -1206,7 +1213,7 @@
1206
1213
 
1207
1214
  const action = router.state.actions[id] || (() => {
1208
1215
  router.state.actions[id] = {
1209
- pending: [],
1216
+ submissions: [],
1210
1217
  submit: async (submission, actionOpts) => {
1211
1218
  var _actionOpts$invalidat;
1212
1219
 
@@ -1215,18 +1222,20 @@
1215
1222
  }
1216
1223
 
1217
1224
  const invalidate = (_actionOpts$invalidat = actionOpts == null ? void 0 : actionOpts.invalidate) != null ? _actionOpts$invalidat : true;
1225
+
1226
+ if (!(actionOpts != null && actionOpts.multi)) {
1227
+ action.submissions = action.submissions.filter(d => d.isMulti);
1228
+ }
1229
+
1218
1230
  const actionState = {
1219
1231
  submittedAt: Date.now(),
1220
1232
  status: 'pending',
1221
- submission
1233
+ submission,
1234
+ isMulti: !!(actionOpts != null && actionOpts.multi)
1222
1235
  };
1223
1236
  action.current = actionState;
1224
1237
  action.latest = actionState;
1225
- action.pending.push(actionState);
1226
- router.state = _extends({}, router.state, {
1227
- currentAction: actionState,
1228
- latestAction: actionState
1229
- });
1238
+ action.submissions.push(actionState);
1230
1239
  router.notify();
1231
1240
 
1232
1241
  try {
@@ -1248,11 +1257,6 @@
1248
1257
  actionState.error = err;
1249
1258
  actionState.status = 'error';
1250
1259
  } finally {
1251
- action.pending = action.pending.filter(d => d !== actionState);
1252
- router.removeActionQueue.push({
1253
- action,
1254
- actionState
1255
- });
1256
1260
  router.notify();
1257
1261
  }
1258
1262
  }
@@ -1260,6 +1264,40 @@
1260
1264
  return router.state.actions[id];
1261
1265
  })();
1262
1266
 
1267
+ const loader = router.state.loaders[id] || (() => {
1268
+ router.state.loaders[id] = {
1269
+ pending: [],
1270
+ fetch: async loaderContext => {
1271
+ if (!route) {
1272
+ return;
1273
+ }
1274
+
1275
+ const loaderState = {
1276
+ loadedAt: Date.now(),
1277
+ loaderContext
1278
+ };
1279
+ loader.current = loaderState;
1280
+ loader.latest = loaderState;
1281
+ loader.pending.push(loaderState); // router.state = {
1282
+ // ...router.state,
1283
+ // currentAction: loaderState,
1284
+ // latestAction: loaderState,
1285
+ // }
1286
+
1287
+ router.notify();
1288
+
1289
+ try {
1290
+ return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
1291
+ } finally {
1292
+ loader.pending = loader.pending.filter(d => d !== loaderState); // router.removeActionQueue.push({ loader, loaderState })
1293
+
1294
+ router.notify();
1295
+ }
1296
+ }
1297
+ };
1298
+ return router.state.loaders[id];
1299
+ })();
1300
+
1263
1301
  let route = {
1264
1302
  routeId: id,
1265
1303
  routeRouteId: routeId,
@@ -1270,6 +1308,7 @@
1270
1308
  childRoutes: undefined,
1271
1309
  parentRoute: parent,
1272
1310
  action,
1311
+ loader: loader,
1273
1312
  buildLink: options => {
1274
1313
  return router.buildLink(_extends({}, options, {
1275
1314
  from: fullPath
@@ -1292,15 +1331,6 @@
1292
1331
  });
1293
1332
  return route;
1294
1333
  }
1295
- function cascadeLoaderData(matches) {
1296
- matches.forEach((match, index) => {
1297
- const parent = matches[index - 1];
1298
-
1299
- if (parent) {
1300
- match.loaderData = replaceEqualDeep(match.loaderData, _extends({}, parent.loaderData, match.routeLoaderData));
1301
- }
1302
- });
1303
- }
1304
1334
 
1305
1335
  const rootRouteId = '__root__';
1306
1336
  const createRouteConfig = function createRouteConfig(options, children, isRoot, parentId, parentPath) {
@@ -1366,6 +1396,7 @@
1366
1396
  isFetching: false,
1367
1397
  isInvalid: false,
1368
1398
  invalidAt: Infinity,
1399
+ // pendingActions: [],
1369
1400
  getIsInvalid: () => {
1370
1401
  const now = Date.now();
1371
1402
  return routeMatch.isInvalid || routeMatch.invalidAt < now;
@@ -1405,17 +1436,6 @@
1405
1436
  clearTimeout(routeMatch.__.pendingMinTimeout);
1406
1437
  delete routeMatch.__.pendingMinPromise;
1407
1438
  },
1408
- // setParentMatch: (parentMatch?: RouteMatch) => {
1409
- // routeMatch.parentMatch = parentMatch
1410
- // },
1411
- // addChildMatch: (childMatch: RouteMatch) => {
1412
- // if (
1413
- // routeMatch.childMatches.find((d) => d.matchId === childMatch.matchId)
1414
- // ) {
1415
- // return
1416
- // }
1417
- // routeMatch.childMatches.push(childMatch)
1418
- // },
1419
1439
  validate: () => {
1420
1440
  var _routeMatch$parentMat, _routeMatch$parentMat2;
1421
1441
 
@@ -1423,9 +1443,11 @@
1423
1443
  const parentSearch = (_routeMatch$parentMat = (_routeMatch$parentMat2 = routeMatch.parentMatch) == null ? void 0 : _routeMatch$parentMat2.search) != null ? _routeMatch$parentMat : router.location.search;
1424
1444
 
1425
1445
  try {
1446
+ var _validator;
1447
+
1426
1448
  const prevSearch = routeMatch.routeSearch;
1427
1449
  const validator = typeof routeMatch.options.validateSearch === 'object' ? routeMatch.options.validateSearch.parse : routeMatch.options.validateSearch;
1428
- let nextSearch = replaceEqualDeep(prevSearch, validator == null ? void 0 : validator(parentSearch)); // Invalidate route matches when search param stability changes
1450
+ let nextSearch = replaceEqualDeep(prevSearch, (_validator = validator == null ? void 0 : validator(parentSearch)) != null ? _validator : {}); // Invalidate route matches when search param stability changes
1429
1451
 
1430
1452
  if (prevSearch !== nextSearch) {
1431
1453
  routeMatch.isInvalid = true;
@@ -1433,6 +1455,13 @@
1433
1455
 
1434
1456
  routeMatch.routeSearch = nextSearch;
1435
1457
  routeMatch.search = replaceEqualDeep(parentSearch, _extends({}, parentSearch, nextSearch));
1458
+ elementTypes.map(async type => {
1459
+ const routeElement = routeMatch.options[type];
1460
+
1461
+ if (typeof routeMatch.__[type] !== 'function') {
1462
+ routeMatch.__[type] = routeElement;
1463
+ }
1464
+ });
1436
1465
  } catch (err) {
1437
1466
  console.error(err);
1438
1467
  const error = new Error('Invalid search params found', {
@@ -1457,9 +1486,33 @@
1457
1486
  routeMatch.isInvalid = true;
1458
1487
  },
1459
1488
  hasLoaders: () => {
1460
- return !!(route.options.loader || route.options.import || elementTypes.some(d => typeof route.options[d] === 'function'));
1489
+ return !!(route.options.loader || elementTypes.some(d => typeof route.options[d] === 'function'));
1490
+ },
1491
+ load: async loaderOpts => {
1492
+ const now = Date.now();
1493
+ 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
1494
+
1495
+ if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
1496
+ // If the match is currently active, don't preload it
1497
+ if (router.state.matches.find(d => d.matchId === routeMatch.matchId)) {
1498
+ return;
1499
+ }
1500
+
1501
+ router.matchCache[routeMatch.matchId] = {
1502
+ gc: now + loaderOpts.gcMaxAge,
1503
+ match: routeMatch
1504
+ };
1505
+ } // If the match is invalid, errored or idle, trigger it to load
1506
+
1507
+
1508
+ if (routeMatch.status === 'success' && routeMatch.getIsInvalid() || routeMatch.status === 'error' || routeMatch.status === 'idle') {
1509
+ const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
1510
+ await routeMatch.fetch({
1511
+ maxAge
1512
+ });
1513
+ }
1461
1514
  },
1462
- load: async opts => {
1515
+ fetch: async opts => {
1463
1516
  const id = '' + Date.now() + Math.random();
1464
1517
  routeMatch.__.latestId = id; // If the match was in an error state, set it
1465
1518
  // to a loading state again. Otherwise, keep it
@@ -1477,37 +1530,16 @@
1477
1530
  routeMatch.isFetching = true;
1478
1531
  routeMatch.__.resolve = resolve;
1479
1532
 
1480
- const loaderPromise = (async () => {
1481
- const importer = routeMatch.options.import; // First, run any importers
1482
-
1483
- if (importer) {
1484
- routeMatch.__.importPromise = importer({
1485
- params: routeMatch.params // search: routeMatch.search,
1486
-
1487
- }).then(imported => {
1488
- routeMatch.__ = _extends({}, routeMatch.__, imported);
1489
- });
1490
- } // Wait for the importer to finish before
1491
- // attempting to load elements and data
1492
-
1493
-
1494
- await routeMatch.__.importPromise; // Next, load the elements and data in parallel
1495
-
1533
+ routeMatch.__.loaderDataPromise = (async () => {
1534
+ // Load the elements and data in parallel
1496
1535
  routeMatch.__.elementsPromise = (async () => {
1497
1536
  // then run all element and data loaders in parallel
1498
1537
  // For each element type, potentially load it asynchronously
1499
1538
  await Promise.all(elementTypes.map(async type => {
1500
1539
  const routeElement = routeMatch.options[type];
1501
1540
 
1502
- if (routeMatch.__[type]) {
1503
- return;
1504
- }
1505
-
1506
- if (typeof routeElement === 'function') {
1507
- const res = await routeElement(routeMatch);
1508
- routeMatch.__[type] = res;
1509
- } else {
1510
- routeMatch.__[type] = routeMatch.options[type];
1541
+ if (typeof routeMatch.__[type] === 'function') {
1542
+ routeMatch.__[type] = await router.options.createElement(routeElement);
1511
1543
  }
1512
1544
  }));
1513
1545
  })();
@@ -1524,7 +1556,7 @@
1524
1556
  });
1525
1557
 
1526
1558
  if (id !== routeMatch.__.latestId) {
1527
- return routeMatch.__.loaderPromise;
1559
+ return routeMatch.__.loadPromise;
1528
1560
  }
1529
1561
 
1530
1562
  routeMatch.routeLoaderData = replaceEqualDeep(routeMatch.routeLoaderData, data);
@@ -1536,7 +1568,7 @@
1536
1568
  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);
1537
1569
  } catch (err) {
1538
1570
  if (id !== routeMatch.__.latestId) {
1539
- return routeMatch.__.loaderPromise;
1571
+ return routeMatch.__.loadPromise;
1540
1572
  }
1541
1573
 
1542
1574
  {
@@ -1553,7 +1585,7 @@
1553
1585
  await Promise.all([routeMatch.__.elementsPromise, routeMatch.__.dataPromise]);
1554
1586
 
1555
1587
  if (id !== routeMatch.__.latestId) {
1556
- return routeMatch.__.loaderPromise;
1588
+ return routeMatch.__.loadPromise;
1557
1589
  }
1558
1590
 
1559
1591
  if (routeMatch.__.pendingMinPromise) {
@@ -1562,7 +1594,7 @@
1562
1594
  }
1563
1595
  } finally {
1564
1596
  if (id !== routeMatch.__.latestId) {
1565
- return routeMatch.__.loaderPromise;
1597
+ return routeMatch.__.loadPromise;
1566
1598
  }
1567
1599
 
1568
1600
  routeMatch.__.cancelPending();
@@ -1574,16 +1606,16 @@
1574
1606
  }
1575
1607
  })();
1576
1608
 
1577
- routeMatch.__.loaderPromise = loaderPromise;
1578
- await loaderPromise;
1609
+ await routeMatch.__.loaderDataPromise;
1579
1610
 
1580
1611
  if (id !== routeMatch.__.latestId) {
1581
- return routeMatch.__.loaderPromise;
1612
+ return routeMatch.__.loadPromise;
1582
1613
  }
1583
1614
 
1584
- delete routeMatch.__.loaderPromise;
1615
+ delete routeMatch.__.loaderDataPromise;
1585
1616
  });
1586
- return await routeMatch.__.loadPromise;
1617
+ await routeMatch.__.loadPromise;
1618
+ delete routeMatch.__.loadPromise;
1587
1619
  }
1588
1620
  });
1589
1621
 
@@ -1644,9 +1676,22 @@
1644
1676
 
1645
1677
  var _window$document;
1646
1678
  // Detect if we're in the DOM
1647
- const isServer = Boolean(typeof window === 'undefined' || !((_window$document = window.document) != null && _window$document.createElement)); // This is the default history object if none is defined
1679
+ const isServer = typeof window === 'undefined' || !((_window$document = window.document) != null && _window$document.createElement); // This is the default history object if none is defined
1680
+
1681
+ const createDefaultHistory = () => isServer ? createMemoryHistory() : createBrowserHistory();
1648
1682
 
1649
- const createDefaultHistory = () => !isServer ? createBrowserHistory() : createMemoryHistory();
1683
+ function getInitialRouterState() {
1684
+ return {
1685
+ status: 'idle',
1686
+ location: null,
1687
+ matches: [],
1688
+ actions: {},
1689
+ loaders: {},
1690
+ lastUpdated: Date.now(),
1691
+ isFetching: false,
1692
+ isPreloading: false
1693
+ };
1694
+ }
1650
1695
 
1651
1696
  function createRouter(userOptions) {
1652
1697
  var _userOptions$stringif, _userOptions$parseSea;
@@ -1664,9 +1709,9 @@
1664
1709
  });
1665
1710
 
1666
1711
  let router = {
1712
+ history,
1667
1713
  options: originalOptions,
1668
1714
  listeners: [],
1669
- removeActionQueue: [],
1670
1715
  // Resolved after construction
1671
1716
  basepath: '',
1672
1717
  routeTree: undefined,
@@ -1677,15 +1722,10 @@
1677
1722
  navigationPromise: Promise.resolve(),
1678
1723
  resolveNavigation: () => {},
1679
1724
  matchCache: {},
1680
- state: {
1681
- status: 'idle',
1682
- location: null,
1683
- matches: [],
1684
- actions: {},
1685
- loaderData: {},
1686
- lastUpdated: Date.now(),
1687
- isFetching: false,
1688
- isPreloading: false
1725
+ state: getInitialRouterState(),
1726
+ reset: () => {
1727
+ router.state = getInitialRouterState();
1728
+ router.notify();
1689
1729
  },
1690
1730
  startedLoadingAt: Date.now(),
1691
1731
  subscribe: listener => {
@@ -1703,24 +1743,44 @@
1703
1743
  isPreloading: Object.values(router.matchCache).some(d => d.match.isFetching && !router.state.matches.find(dd => dd.matchId === d.match.matchId))
1704
1744
  });
1705
1745
  cascadeLoaderData(router.state.matches);
1706
- router.listeners.forEach(listener => listener());
1746
+ router.listeners.forEach(listener => listener(router));
1747
+ },
1748
+ dehydrateState: () => {
1749
+ return _extends({}, pick(router.state, ['status', 'location', 'lastUpdated']), {
1750
+ matches: router.state.matches.map(match => pick(match, ['matchId', 'status', 'routeLoaderData', 'loaderData', 'isInvalid', 'invalidAt']))
1751
+ });
1752
+ },
1753
+ hydrateState: dehydratedState => {
1754
+ // Match the routes
1755
+ const matches = router.matchRoutes(router.location.pathname, {
1756
+ strictParseParams: true
1757
+ });
1758
+ matches.forEach((match, index) => {
1759
+ const dehydratedMatch = dehydratedState.matches[index];
1760
+ invariant(dehydratedMatch, 'Oh no! Dehydrated route matches did not match the active state of the router 😬');
1761
+ Object.assign(match, dehydratedMatch);
1762
+ });
1763
+ router.loadMatches(matches);
1764
+ router.state = _extends({}, router.state, dehydratedState, {
1765
+ matches
1766
+ });
1707
1767
  },
1708
1768
  mount: () => {
1709
- const next = router.buildLocation({
1769
+ const next = router.__.buildLocation({
1710
1770
  to: '.',
1711
1771
  search: true,
1712
1772
  hash: true
1713
1773
  }); // If the current location isn't updated, trigger a navigation
1714
1774
  // to the current location. Otherwise, load the current location.
1715
1775
 
1776
+
1716
1777
  if (next.href !== router.location.href) {
1717
- router.commitLocation(next, true);
1718
- } else {
1719
- router.loadLocation();
1720
- }
1778
+ router.__.commitLocation(next, true);
1779
+ } // router.load()
1721
1780
 
1722
- const unsub = history.listen(event => {
1723
- router.loadLocation(router.parseLocation(event.location, router.location));
1781
+
1782
+ const unsub = router.history.listen(event => {
1783
+ router.load(router.__.parseLocation(event.location, router.location));
1724
1784
  }); // addEventListener does not exist in React Native, but window does
1725
1785
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1726
1786
 
@@ -1731,16 +1791,30 @@
1731
1791
  }
1732
1792
 
1733
1793
  return () => {
1734
- unsub(); // Be sure to unsubscribe if a new handler is set
1794
+ unsub();
1735
1795
 
1736
- window.removeEventListener('visibilitychange', router.onFocus);
1737
- window.removeEventListener('focus', router.onFocus);
1796
+ if (!isServer && window.removeEventListener) {
1797
+ // Be sure to unsubscribe if a new handler is set
1798
+ window.removeEventListener('visibilitychange', router.onFocus);
1799
+ window.removeEventListener('focus', router.onFocus);
1800
+ }
1738
1801
  };
1739
1802
  },
1740
1803
  onFocus: () => {
1741
- router.loadLocation();
1804
+ router.load();
1742
1805
  },
1743
1806
  update: opts => {
1807
+ const newHistory = (opts == null ? void 0 : opts.history) !== router.history;
1808
+
1809
+ if (!router.location || newHistory) {
1810
+ if (opts != null && opts.history) {
1811
+ router.history = opts.history;
1812
+ }
1813
+
1814
+ router.location = router.__.parseLocation(router.history.location);
1815
+ router.state.location = router.location;
1816
+ }
1817
+
1744
1818
  Object.assign(router.options, opts);
1745
1819
  const {
1746
1820
  basepath,
@@ -1750,204 +1824,30 @@
1750
1824
 
1751
1825
  if (routeConfig) {
1752
1826
  router.routesById = {};
1753
- router.routeTree = router.buildRouteTree(routeConfig);
1827
+ router.routeTree = router.__.buildRouteTree(routeConfig);
1754
1828
  }
1755
1829
 
1756
1830
  return router;
1757
1831
  },
1758
- buildRouteTree: rootRouteConfig => {
1759
- const recurseRoutes = (routeConfigs, parent) => {
1760
- return routeConfigs.map(routeConfig => {
1761
- const routeOptions = routeConfig.options;
1762
- const route = createRoute(routeConfig, routeOptions, parent, router); // {
1763
- // pendingMs: routeOptions.pendingMs ?? router.defaultPendingMs,
1764
- // pendingMinMs: routeOptions.pendingMinMs ?? router.defaultPendingMinMs,
1765
- // }
1766
-
1767
- const existingRoute = router.routesById[route.routeId];
1768
-
1769
- if (existingRoute) {
1770
- {
1771
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
1772
- }
1773
-
1774
- throw new Error();
1775
- }
1776
- router.routesById[route.routeId] = route;
1777
- const children = routeConfig.children;
1778
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
1779
- return route;
1780
- });
1781
- };
1782
-
1783
- const routes = recurseRoutes([rootRouteConfig]);
1784
- return routes[0];
1785
- },
1786
- parseLocation: (location, previousLocation) => {
1787
- var _location$hash$split$;
1788
-
1789
- const parsedSearch = router.options.parseSearch(location.search);
1790
- return {
1791
- pathname: location.pathname,
1792
- searchStr: location.search,
1793
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
1794
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
1795
- href: "" + location.pathname + location.search + location.hash,
1796
- state: location.state,
1797
- key: location.key
1798
- };
1799
- },
1800
- buildLocation: function buildLocation(dest) {
1801
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
1802
-
1803
- if (dest === void 0) {
1804
- dest = {};
1805
- }
1806
-
1807
- // const resolvedFrom: Location = {
1808
- // ...router.location,
1809
- const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
1810
-
1811
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
1812
-
1813
- const fromMatches = router.matchRoutes(router.location.pathname, {
1814
- strictParseParams: true
1815
- });
1816
- const toMatches = router.matchRoutes(pathname);
1817
-
1818
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
1819
-
1820
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1821
-
1822
- if (nextParams) {
1823
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
1824
- Object.assign({}, nextParams, fn(nextParams));
1825
- });
1826
- }
1827
-
1828
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
1829
-
1830
- 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
1831
-
1832
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1833
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
1834
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
1835
- : {}; // Then post filters
1836
-
1837
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1838
- const search = replaceEqualDeep(router.location.search, postFilteredSearch);
1839
- const searchStr = router.options.stringifySearch(search);
1840
- let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
1841
- hash = hash ? "#" + hash : '';
1842
- return {
1843
- pathname,
1844
- search,
1845
- searchStr,
1846
- state: router.location.state,
1847
- hash,
1848
- href: "" + pathname + searchStr + hash,
1849
- key: dest.key
1850
- };
1851
- },
1852
- commitLocation: (next, replace) => {
1853
- const id = '' + Date.now() + Math.random();
1854
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
1855
- let nextAction = 'replace';
1856
-
1857
- if (!replace) {
1858
- nextAction = 'push';
1859
- }
1860
-
1861
- const isSameUrl = router.parseLocation(history.location).href === next.href;
1862
-
1863
- if (isSameUrl && !next.key) {
1864
- nextAction = 'replace';
1865
- }
1866
-
1867
- if (nextAction === 'replace') {
1868
- history.replace({
1869
- pathname: next.pathname,
1870
- hash: next.hash,
1871
- search: next.searchStr
1872
- }, {
1873
- id
1874
- });
1875
- } else {
1876
- history.push({
1877
- pathname: next.pathname,
1878
- hash: next.hash,
1879
- search: next.searchStr
1880
- }, {
1881
- id
1882
- });
1883
- }
1884
-
1885
- router.navigationPromise = new Promise(resolve => {
1886
- const previousNavigationResolve = router.resolveNavigation;
1887
-
1888
- router.resolveNavigation = () => {
1889
- previousNavigationResolve();
1890
- resolve();
1891
- };
1892
- });
1893
- return router.navigationPromise;
1894
- },
1895
- buildNext: opts => {
1896
- const next = router.buildLocation(opts);
1897
- const matches = router.matchRoutes(next.pathname);
1898
-
1899
- const __preSearchFilters = matches.map(match => {
1900
- var _match$options$preSea;
1901
-
1902
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
1903
- }).flat().filter(Boolean);
1904
-
1905
- const __postSearchFilters = matches.map(match => {
1906
- var _match$options$postSe;
1907
-
1908
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
1909
- }).flat().filter(Boolean);
1910
-
1911
- return router.buildLocation(_extends({}, opts, {
1912
- __preSearchFilters,
1913
- __postSearchFilters
1914
- }));
1915
- },
1916
1832
  cancelMatches: () => {
1917
1833
  var _router$state$pending, _router$state$pending2;
1918
1834
  [...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 => {
1919
1835
  match.cancel();
1920
1836
  });
1921
1837
  },
1922
- loadLocation: async next => {
1838
+ load: async next => {
1923
1839
  const id = Math.random();
1924
1840
  router.startedLoadingAt = id;
1925
1841
 
1926
1842
  if (next) {
1927
1843
  // Ingest the new location
1928
1844
  router.location = next;
1929
- } // Clear out old actions
1930
-
1931
-
1932
- router.removeActionQueue.forEach(_ref => {
1933
- let {
1934
- action,
1935
- actionState
1936
- } = _ref;
1937
-
1938
- if (router.state.currentAction === actionState) {
1939
- router.state.currentAction = undefined;
1940
- }
1845
+ } // Cancel any pending matches
1941
1846
 
1942
- if (action.current === actionState) {
1943
- action.current = undefined;
1944
- }
1945
- });
1946
- router.removeActionQueue = []; // Cancel any pending matches
1947
1847
 
1948
1848
  router.cancelMatches(); // Match the routes
1949
1849
 
1950
- const matches = router.matchRoutes(location.pathname, {
1850
+ const matches = router.matchRoutes(router.location.pathname, {
1951
1851
  strictParseParams: true
1952
1852
  });
1953
1853
  router.state = _extends({}, router.state, {
@@ -1980,19 +1880,24 @@
1980
1880
  });
1981
1881
  const now = Date.now();
1982
1882
  exiting.forEach(d => {
1983
- var _ref2, _d$options$loaderGcMa, _ref3, _d$options$loaderMaxA;
1883
+ var _ref, _d$options$loaderGcMa, _ref2, _d$options$loaderMaxA;
1984
1884
 
1985
1885
  d.__.onExit == null ? void 0 : d.__.onExit({
1986
1886
  params: d.params,
1987
1887
  search: d.routeSearch
1988
- }); // Clear idle error states when match leaves
1888
+ }); // // Clear actions
1889
+ // if (d.action) {
1890
+ // d.action.current = undefined
1891
+ // d.action.submissions = []
1892
+ // }
1893
+ // Clear idle error states when match leaves
1989
1894
 
1990
1895
  if (d.status === 'error' && !d.isFetching) {
1991
1896
  d.status = 'idle';
1992
1897
  d.error = undefined;
1993
1898
  }
1994
1899
 
1995
- const gc = Math.max((_ref2 = (_d$options$loaderGcMa = d.options.loaderGcMaxAge) != null ? _d$options$loaderGcMa : router.options.defaultLoaderGcMaxAge) != null ? _ref2 : 0, (_ref3 = (_d$options$loaderMaxA = d.options.loaderMaxAge) != null ? _d$options$loaderMaxA : router.options.defaultLoaderMaxAge) != null ? _ref3 : 0);
1900
+ const gc = Math.max((_ref = (_d$options$loaderGcMa = d.options.loaderGcMaxAge) != null ? _d$options$loaderGcMa : router.options.defaultLoaderGcMaxAge) != null ? _ref : 0, (_ref2 = (_d$options$loaderMaxA = d.options.loaderMaxAge) != null ? _d$options$loaderMaxA : router.options.defaultLoaderMaxAge) != null ? _ref2 : 0);
1996
1901
 
1997
1902
  if (gc > 0) {
1998
1903
  router.matchCache[d.matchId] = {
@@ -2015,18 +1920,21 @@
2015
1920
  params: d.params,
2016
1921
  search: d.search
2017
1922
  });
2018
- });
2019
-
2020
- if (matches.some(d => d.status === 'loading')) {
2021
- router.notify();
2022
- await Promise.all(matches.map(d => d.__.loaderPromise || Promise.resolve()));
2023
- }
1923
+ delete router.matchCache[d.matchId];
1924
+ }); // router.notify()
2024
1925
 
2025
1926
  if (router.startedLoadingAt !== id) {
2026
1927
  // Ignore side-effects of match loading
2027
1928
  return;
2028
1929
  }
2029
1930
 
1931
+ matches.forEach(match => {
1932
+ // Clear actions
1933
+ if (match.action) {
1934
+ match.action.current = undefined;
1935
+ match.action.submissions = [];
1936
+ }
1937
+ });
2030
1938
  router.state = _extends({}, router.state, {
2031
1939
  location: router.location,
2032
1940
  matches,
@@ -2067,7 +1975,7 @@
2067
1975
  return matches;
2068
1976
  },
2069
1977
  preloadRoute: async function preloadRoute(navigateOpts, loaderOpts) {
2070
- var _ref4, _ref5, _loaderOpts$maxAge, _ref6, _ref7, _loaderOpts$gcMaxAge;
1978
+ var _ref3, _ref4, _loaderOpts$maxAge, _ref5, _ref6, _loaderOpts$gcMaxAge;
2071
1979
 
2072
1980
  if (navigateOpts === void 0) {
2073
1981
  navigateOpts = router.location;
@@ -2079,8 +1987,8 @@
2079
1987
  });
2080
1988
  await router.loadMatches(matches, {
2081
1989
  preload: true,
2082
- maxAge: (_ref4 = (_ref5 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref5 : router.options.defaultLoaderMaxAge) != null ? _ref4 : 0,
2083
- gcMaxAge: (_ref6 = (_ref7 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref7 : router.options.defaultLoaderGcMaxAge) != null ? _ref6 : 0
1990
+ maxAge: (_ref3 = (_ref4 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref4 : router.options.defaultLoaderMaxAge) != null ? _ref3 : 0,
1991
+ gcMaxAge: (_ref5 = (_ref6 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref6 : router.options.defaultLoaderGcMaxAge) != null ? _ref5 : 0
2084
1992
  });
2085
1993
  return matches;
2086
1994
  },
@@ -2174,38 +2082,20 @@
2174
2082
  return matches;
2175
2083
  },
2176
2084
  loadMatches: async (resolvedMatches, loaderOpts) => {
2177
- const now = Date.now();
2178
- const minMaxAge = loaderOpts != null && loaderOpts.preload ? Math.max(loaderOpts == null ? void 0 : loaderOpts.maxAge, loaderOpts == null ? void 0 : loaderOpts.gcMaxAge) : 0;
2179
2085
  const matchPromises = resolvedMatches.map(async match => {
2180
2086
  // Validate the match (loads search params etc)
2181
- match.__.validate(); // If this is a preload, add it to the preload cache
2182
-
2183
-
2184
- if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
2185
- // If the match is currently active, don't preload it
2186
- if (router.state.matches.find(d => d.matchId === match.matchId)) {
2187
- return;
2188
- }
2189
-
2190
- router.matchCache[match.matchId] = {
2191
- gc: now + loaderOpts.gcMaxAge,
2192
- match
2193
- };
2194
- } // If the match is invalid, errored or idle, trigger it to load
2195
-
2087
+ match.__.validate();
2196
2088
 
2197
- if (match.status === 'success' && match.getIsInvalid() || match.status === 'error' || match.status === 'idle') {
2198
- const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
2199
- match.load({
2200
- maxAge
2201
- });
2202
- }
2089
+ match.load(loaderOpts);
2203
2090
 
2204
2091
  if (match.status === 'loading') {
2205
2092
  // If requested, start the pending timers
2206
- if (loaderOpts != null && loaderOpts.withPending) match.__.startPending(); // Wait for the first sign of activity from the match
2207
- // This might be completion, error, or a pending state
2093
+ if (loaderOpts != null && loaderOpts.withPending) match.__.startPending();
2094
+ }
2208
2095
 
2096
+ if (match.__.loadPromise) {
2097
+ // Wait for the first sign of activity from the match
2098
+ // This might be completion, error, or a pending state
2209
2099
  await match.__.loadPromise;
2210
2100
  }
2211
2101
  });
@@ -2223,7 +2113,7 @@
2223
2113
  }
2224
2114
  });
2225
2115
  },
2226
- reload: () => router._navigate({
2116
+ reload: () => router.__.navigate({
2227
2117
  fromCurrent: true,
2228
2118
  replace: true,
2229
2119
  search: true
@@ -2256,11 +2146,7 @@
2256
2146
  to: next.pathname
2257
2147
  }));
2258
2148
  },
2259
- _navigate: location => {
2260
- const next = router.buildNext(location);
2261
- return router.commitLocation(next, location.replace);
2262
- },
2263
- navigate: async _ref8 => {
2149
+ navigate: async _ref7 => {
2264
2150
  let {
2265
2151
  from,
2266
2152
  to = '.',
@@ -2268,7 +2154,7 @@
2268
2154
  hash,
2269
2155
  replace,
2270
2156
  params
2271
- } = _ref8;
2157
+ } = _ref7;
2272
2158
  // If this link simply reloads the current route,
2273
2159
  // make sure it has a new key so it will trigger a data refresh
2274
2160
  // If this `to` is a valid external URL, return
@@ -2283,7 +2169,7 @@
2283
2169
  } catch (e) {}
2284
2170
 
2285
2171
  invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2286
- return router._navigate({
2172
+ return router.__.navigate({
2287
2173
  from: fromString,
2288
2174
  to: toString,
2289
2175
  search,
@@ -2292,8 +2178,8 @@
2292
2178
  params
2293
2179
  });
2294
2180
  },
2295
- buildLink: _ref9 => {
2296
- var _preload, _ref10;
2181
+ buildLink: _ref8 => {
2182
+ var _preload, _ref9;
2297
2183
 
2298
2184
  let {
2299
2185
  from,
@@ -2309,7 +2195,7 @@
2309
2195
  preloadGcMaxAge: userPreloadGcMaxAge,
2310
2196
  preloadDelay: userPreloadDelay,
2311
2197
  disabled
2312
- } = _ref9;
2198
+ } = _ref8;
2313
2199
 
2314
2200
  // If this link simply reloads the current route,
2315
2201
  // make sure it has a new key so it will trigger a data refresh
@@ -2333,7 +2219,7 @@
2333
2219
  };
2334
2220
  const next = router.buildNext(nextOpts);
2335
2221
  preload = (_preload = preload) != null ? _preload : router.options.defaultPreload;
2336
- const preloadDelay = (_ref10 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultPreloadDelay) != null ? _ref10 : 0; // Compare path/hash for matches
2222
+ const preloadDelay = (_ref9 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultPreloadDelay) != null ? _ref9 : 0; // Compare path/hash for matches
2337
2223
 
2338
2224
  const pathIsEqual = router.state.location.pathname === next.pathname;
2339
2225
  const currentPathSplit = router.state.location.pathname.split('/');
@@ -2355,7 +2241,7 @@
2355
2241
  } // All is well? Navigate!)
2356
2242
 
2357
2243
 
2358
- router._navigate(nextOpts);
2244
+ router.__.navigate(nextOpts);
2359
2245
  }
2360
2246
  }; // The click handler
2361
2247
 
@@ -2406,10 +2292,169 @@
2406
2292
  isActive,
2407
2293
  disabled
2408
2294
  };
2295
+ },
2296
+ buildNext: opts => {
2297
+ const next = router.__.buildLocation(opts);
2298
+
2299
+ const matches = router.matchRoutes(next.pathname);
2300
+
2301
+ const __preSearchFilters = matches.map(match => {
2302
+ var _match$options$preSea;
2303
+
2304
+ return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
2305
+ }).flat().filter(Boolean);
2306
+
2307
+ const __postSearchFilters = matches.map(match => {
2308
+ var _match$options$postSe;
2309
+
2310
+ return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
2311
+ }).flat().filter(Boolean);
2312
+
2313
+ return router.__.buildLocation(_extends({}, opts, {
2314
+ __preSearchFilters,
2315
+ __postSearchFilters
2316
+ }));
2317
+ },
2318
+ __: {
2319
+ buildRouteTree: rootRouteConfig => {
2320
+ const recurseRoutes = (routeConfigs, parent) => {
2321
+ return routeConfigs.map(routeConfig => {
2322
+ const routeOptions = routeConfig.options;
2323
+ const route = createRoute(routeConfig, routeOptions, parent, router);
2324
+ const existingRoute = router.routesById[route.routeId];
2325
+
2326
+ if (existingRoute) {
2327
+ {
2328
+ console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
2329
+ }
2330
+
2331
+ throw new Error();
2332
+ }
2333
+ router.routesById[route.routeId] = route;
2334
+ const children = routeConfig.children;
2335
+ route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
2336
+ return route;
2337
+ });
2338
+ };
2339
+
2340
+ const routes = recurseRoutes([rootRouteConfig]);
2341
+ return routes[0];
2342
+ },
2343
+ parseLocation: (location, previousLocation) => {
2344
+ var _location$hash$split$;
2345
+
2346
+ const parsedSearch = router.options.parseSearch(location.search);
2347
+ return {
2348
+ pathname: location.pathname,
2349
+ searchStr: location.search,
2350
+ search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
2351
+ hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
2352
+ href: "" + location.pathname + location.search + location.hash,
2353
+ state: location.state,
2354
+ key: location.key
2355
+ };
2356
+ },
2357
+ navigate: location => {
2358
+ const next = router.buildNext(location);
2359
+ return router.__.commitLocation(next, location.replace);
2360
+ },
2361
+ buildLocation: function buildLocation(dest) {
2362
+ var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
2363
+
2364
+ if (dest === void 0) {
2365
+ dest = {};
2366
+ }
2367
+
2368
+ // const resolvedFrom: Location = {
2369
+ // ...router.location,
2370
+ const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
2371
+
2372
+ let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
2373
+
2374
+ const fromMatches = router.matchRoutes(router.location.pathname, {
2375
+ strictParseParams: true
2376
+ });
2377
+ const toMatches = router.matchRoutes(pathname);
2378
+
2379
+ const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
2380
+
2381
+ let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
2382
+
2383
+ if (nextParams) {
2384
+ toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
2385
+ Object.assign({}, nextParams, fn(nextParams));
2386
+ });
2387
+ }
2388
+
2389
+ pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
2390
+
2391
+ 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
2392
+
2393
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
2394
+ : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
2395
+ : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
2396
+ : {}; // Then post filters
2397
+
2398
+ const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
2399
+ const search = replaceEqualDeep(router.location.search, postFilteredSearch);
2400
+ const searchStr = router.options.stringifySearch(search);
2401
+ let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
2402
+ hash = hash ? "#" + hash : '';
2403
+ return {
2404
+ pathname,
2405
+ search,
2406
+ searchStr,
2407
+ state: router.location.state,
2408
+ hash,
2409
+ href: "" + pathname + searchStr + hash,
2410
+ key: dest.key
2411
+ };
2412
+ },
2413
+ commitLocation: (next, replace) => {
2414
+ const id = '' + Date.now() + Math.random();
2415
+ if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
2416
+ let nextAction = 'replace';
2417
+
2418
+ if (!replace) {
2419
+ nextAction = 'push';
2420
+ }
2421
+
2422
+ const isSameUrl = router.__.parseLocation(history.location).href === next.href;
2423
+
2424
+ if (isSameUrl && !next.key) {
2425
+ nextAction = 'replace';
2426
+ }
2427
+
2428
+ if (nextAction === 'replace') {
2429
+ history.replace({
2430
+ pathname: next.pathname,
2431
+ hash: next.hash,
2432
+ search: next.searchStr
2433
+ }, {
2434
+ id
2435
+ });
2436
+ } else {
2437
+ history.push({
2438
+ pathname: next.pathname,
2439
+ hash: next.hash,
2440
+ search: next.searchStr
2441
+ }, {
2442
+ id
2443
+ });
2444
+ }
2445
+
2446
+ router.navigationPromise = new Promise(resolve => {
2447
+ const previousNavigationResolve = router.resolveNavigation;
2448
+
2449
+ router.resolveNavigation = () => {
2450
+ previousNavigationResolve();
2451
+ resolve();
2452
+ };
2453
+ });
2454
+ return router.navigationPromise;
2455
+ }
2409
2456
  }
2410
2457
  };
2411
- router.location = router.parseLocation(history.location);
2412
- router.state.location = router.location;
2413
2458
  router.update(userOptions); // Allow frameworks to hook into the router creation
2414
2459
 
2415
2460
  router.options.createRouter == null ? void 0 : router.options.createRouter(router);
@@ -2420,7 +2465,16 @@
2420
2465
  return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
2421
2466
  }
2422
2467
 
2423
- exports.cascadeLoaderData = cascadeLoaderData;
2468
+ function cascadeLoaderData(matches) {
2469
+ matches.forEach((match, index) => {
2470
+ const parent = matches[index - 1];
2471
+
2472
+ if (parent) {
2473
+ match.loaderData = replaceEqualDeep(match.loaderData, _extends({}, parent.loaderData, match.routeLoaderData));
2474
+ }
2475
+ });
2476
+ }
2477
+
2424
2478
  exports.cleanPath = cleanPath;
2425
2479
  exports.createBrowserHistory = createBrowserHistory;
2426
2480
  exports.createHashHistory = createHashHistory;
@@ -2442,6 +2496,7 @@
2442
2496
  exports.matchPathname = matchPathname;
2443
2497
  exports.parsePathname = parsePathname;
2444
2498
  exports.parseSearchWith = parseSearchWith;
2499
+ exports.pick = pick;
2445
2500
  exports.replaceEqualDeep = replaceEqualDeep;
2446
2501
  exports.resolvePath = resolvePath;
2447
2502
  exports.rootRouteId = rootRouteId;