@tanstack/react-router 0.0.1-beta.165 → 0.0.1-beta.167

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.
@@ -726,6 +726,15 @@
726
726
 
727
727
  // The parse type here allows a zod schema to be passed directly to the validator
728
728
 
729
+ // T extends Record<PropertyKey, infer U>
730
+ // ? {
731
+ // [K in keyof T]: UseLoaderResultPromise<T[K]>
732
+ // }
733
+ // : UseLoaderResultPromise<T>
734
+
735
+ // export type UseLoaderResultPromise<T> = T extends Promise<infer U>
736
+ // ? StreamedPromise<U>
737
+ // : T
729
738
  class Route {
730
739
  // Set up in this.init()
731
740
 
@@ -988,7 +997,7 @@
988
997
  } = this.options;
989
998
  this.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
990
999
  if (routeTree && routeTree !== this.routeTree) {
991
- this.#buildRouteTree(routeTree);
1000
+ this.#processRoutes(routeTree);
992
1001
  }
993
1002
  return this;
994
1003
  };
@@ -1224,8 +1233,8 @@
1224
1233
  params: routeParams,
1225
1234
  pathname: joinPaths([this.basepath, interpolatedPath]),
1226
1235
  updatedAt: Date.now(),
1227
- invalidAt: Infinity,
1228
- preloadInvalidAt: Infinity,
1236
+ invalidAt: 9999999999999,
1237
+ preloadInvalidAt: 9999999999999,
1229
1238
  routeSearch: {},
1230
1239
  search: {},
1231
1240
  status: hasLoaders ? 'pending' : 'success',
@@ -1639,7 +1648,9 @@
1639
1648
  };
1640
1649
  dehydrate = () => {
1641
1650
  return {
1642
- state: pick(this.state, ['location', 'status', 'lastUpdated'])
1651
+ state: {
1652
+ dehydratedMatches: this.state.matches.map(d => pick(d, ['fetchedAt', 'invalid', 'invalidAt', 'id', 'loaderData', 'status', 'updatedAt']))
1653
+ }
1643
1654
  };
1644
1655
  };
1645
1656
  hydrate = async __do_not_use_server_ctx => {
@@ -1652,16 +1663,27 @@
1652
1663
  const ctx = _ctx;
1653
1664
  this.dehydratedData = ctx.payload;
1654
1665
  this.options.hydrate?.(ctx.payload);
1655
- const routerState = ctx.router.state;
1666
+ const {
1667
+ dehydratedMatches
1668
+ } = ctx.router.state;
1669
+ let matches = this.matchRoutes(this.state.location.pathname, this.state.location.search).map(match => {
1670
+ const dehydratedMatch = dehydratedMatches.find(d => d.id === match.id);
1671
+ invariant(dehydratedMatch, `Could not find a client-side match for dehydrated match with id: ${match.id}!`);
1672
+ if (dehydratedMatch) {
1673
+ return {
1674
+ ...match,
1675
+ ...dehydratedMatch
1676
+ };
1677
+ }
1678
+ return match;
1679
+ });
1656
1680
  this.__store.setState(s => {
1657
1681
  return {
1658
1682
  ...s,
1659
- ...routerState,
1660
- resolvedLocation: routerState.location
1683
+ matches,
1684
+ matchesById: this.#mergeMatches(s.matchesById, matches)
1661
1685
  };
1662
1686
  });
1663
- await this.load();
1664
- return;
1665
1687
  };
1666
1688
  injectedHtml = [];
1667
1689
  injectHtml = async html => {
@@ -1674,10 +1696,10 @@
1674
1696
  const id = `__TSR_DEHYDRATED__${strKey}`;
1675
1697
  const data = typeof getData === 'function' ? await getData() : getData;
1676
1698
  return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
1677
- ;(() => {
1678
- var el = document.getElementById('${id}')
1679
- el.parentElement.removeChild(el)
1680
- })()
1699
+ // ;(() => {
1700
+ // var el = document.getElementById('${id}')
1701
+ // el.parentElement.removeChild(el)
1702
+ // })()
1681
1703
  </script>`;
1682
1704
  });
1683
1705
  return () => this.hydrateData(key);
@@ -1698,7 +1720,7 @@
1698
1720
  // ?.__promisesByKey[key]?.resolve(value)
1699
1721
  // }
1700
1722
 
1701
- #buildRouteTree = routeTree => {
1723
+ #processRoutes = routeTree => {
1702
1724
  this.routeTree = routeTree;
1703
1725
  this.routesById = {};
1704
1726
  this.routesByPath = {};
@@ -1890,7 +1912,7 @@
1890
1912
  const route = this.getRoute(match.routeId);
1891
1913
  const updatedAt = opts?.updatedAt ?? Date.now();
1892
1914
  const preloadInvalidAt = updatedAt + (opts?.maxAge ?? route.options.preloadMaxAge ?? this.options.defaultPreloadMaxAge ?? 5000);
1893
- const invalidAt = updatedAt + (opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? Infinity);
1915
+ const invalidAt = updatedAt + (opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? 9999999999999);
1894
1916
  this.setRouteMatch(id, s => ({
1895
1917
  ...s,
1896
1918
  error: undefined,
@@ -2110,6 +2132,28 @@
2110
2132
  }
2111
2133
  }
2112
2134
 
2135
+ function defer(_promise) {
2136
+ const promise = _promise;
2137
+ if (!promise.__deferredState) {
2138
+ promise.__deferredState = {
2139
+ uid: Math.random().toString(36).slice(2),
2140
+ status: 'pending'
2141
+ };
2142
+ const state = promise.__deferredState;
2143
+ promise.then(data => {
2144
+ state.status = 'success';
2145
+ state.data = data;
2146
+ }).catch(error => {
2147
+ state.status = 'error';
2148
+ state.error = error;
2149
+ });
2150
+ }
2151
+ return promise;
2152
+ }
2153
+ function isDehydratedDeferred(obj) {
2154
+ return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
2155
+ }
2156
+
2113
2157
  const useLayoutEffect = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
2114
2158
  function useScrollRestoration(options) {
2115
2159
  const router = useRouter();
@@ -2125,6 +2169,31 @@
2125
2169
  return null;
2126
2170
  }
2127
2171
 
2172
+ function useDeferred({
2173
+ promise
2174
+ }) {
2175
+ const router = useRouter();
2176
+ let state = promise.__deferredState;
2177
+ const key = `__TSR__DEFERRED__${state.uid}`;
2178
+ if (isDehydratedDeferred(promise)) {
2179
+ state = router.hydrateData(key);
2180
+ promise = Promise.resolve(state.data);
2181
+ promise.__deferredState = state;
2182
+ }
2183
+ if (state.status === 'pending') {
2184
+ throw promise;
2185
+ }
2186
+ if (state.status === 'error') {
2187
+ throw state.error;
2188
+ }
2189
+ router.dehydrateData(key, state);
2190
+ return [state.data];
2191
+ }
2192
+ function Deferred(props) {
2193
+ const awaited = useDeferred(props);
2194
+ return props.children(...awaited);
2195
+ }
2196
+
2128
2197
  Route.__onInit = route => {
2129
2198
  Object.assign(route, {
2130
2199
  useMatch: (opts = {}) => {
@@ -2319,11 +2388,9 @@
2319
2388
  return unsub;
2320
2389
  }, [router]);
2321
2390
  const Wrap = router.options.Wrap || React__namespace.Fragment;
2322
- return /*#__PURE__*/React__namespace.createElement(React__namespace.Suspense, {
2323
- fallback: null
2324
- }, /*#__PURE__*/React__namespace.createElement(Wrap, null, /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
2391
+ return /*#__PURE__*/React__namespace.createElement(Wrap, null, /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
2325
2392
  value: router
2326
- }, /*#__PURE__*/React__namespace.createElement(Matches, null))));
2393
+ }, /*#__PURE__*/React__namespace.createElement(Matches, null)));
2327
2394
  }
2328
2395
  function Matches() {
2329
2396
  const router = useRouter();
@@ -2343,6 +2410,7 @@
2343
2410
  value: [undefined, ...matchIds]
2344
2411
  }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
2345
2412
  errorComponent: ErrorComponent,
2413
+ route: router.getRoute(rootRouteId),
2346
2414
  onCatch: () => {
2347
2415
  warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
2348
2416
  }
@@ -2476,7 +2544,6 @@
2476
2544
  value: matchIds
2477
2545
  }, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
2478
2546
  fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, {
2479
- useLoader: route.useLoader,
2480
2547
  useMatch: route.useMatch,
2481
2548
  useContext: route.useContext,
2482
2549
  useRouteContext: route.useRouteContext,
@@ -2486,6 +2553,7 @@
2486
2553
  }, /*#__PURE__*/React__namespace.createElement(ResolvedCatchBoundary, {
2487
2554
  key: route.id,
2488
2555
  errorComponent: errorComponent,
2556
+ route: route,
2489
2557
  onCatch: () => {
2490
2558
  warning(false, `Error in route match: ${matchId}`);
2491
2559
  }
@@ -2602,7 +2670,14 @@
2602
2670
  // props.reset()
2603
2671
  }, [props.errorState.error]);
2604
2672
  if (props.errorState.error && activeErrorState.error) {
2605
- return /*#__PURE__*/React__namespace.createElement(errorComponent, activeErrorState);
2673
+ return /*#__PURE__*/React__namespace.createElement(errorComponent, {
2674
+ ...activeErrorState,
2675
+ useMatch: props.route.useMatch,
2676
+ useContext: props.route.useContext,
2677
+ useRouteContext: props.route.useRouteContext,
2678
+ useSearch: props.route.useSearch,
2679
+ useParams: props.route.useParams
2680
+ });
2606
2681
  }
2607
2682
  return props.children;
2608
2683
  }
@@ -2691,6 +2766,7 @@
2691
2766
  }
2692
2767
 
2693
2768
  exports.Block = Block;
2769
+ exports.Deferred = Deferred;
2694
2770
  exports.ErrorComponent = ErrorComponent;
2695
2771
  exports.FileRoute = FileRoute;
2696
2772
  exports.Link = Link;
@@ -2713,10 +2789,12 @@
2713
2789
  exports.decode = decode;
2714
2790
  exports.defaultParseSearch = defaultParseSearch;
2715
2791
  exports.defaultStringifySearch = defaultStringifySearch;
2792
+ exports.defer = defer;
2716
2793
  exports.encode = encode;
2717
2794
  exports.functionalUpdate = functionalUpdate;
2718
2795
  exports.interpolatePath = interpolatePath;
2719
2796
  exports.invariant = invariant;
2797
+ exports.isDehydratedDeferred = isDehydratedDeferred;
2720
2798
  exports.isPlainObject = isPlainObject;
2721
2799
  exports.isRedirect = isRedirect;
2722
2800
  exports.joinPaths = joinPaths;
@@ -2742,6 +2820,7 @@
2742
2820
  exports.trimPathLeft = trimPathLeft;
2743
2821
  exports.trimPathRight = trimPathRight;
2744
2822
  exports.useBlocker = useBlocker;
2823
+ exports.useDeferred = useDeferred;
2745
2824
  exports.useDehydrate = useDehydrate;
2746
2825
  exports.useHydrate = useHydrate;
2747
2826
  exports.useInjectHtml = useInjectHtml;