react-router 8.3.0 → 8.4.0

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.
Files changed (176) hide show
  1. package/CHANGELOG.md +46 -2
  2. package/dist/development/dom-export.js +1 -1
  3. package/dist/development/index-react-server-client.js +1 -1
  4. package/dist/development/index-react-server.d.ts +50 -48
  5. package/dist/development/index-react-server.js +96 -43
  6. package/dist/development/index.d.ts +2 -2
  7. package/dist/development/index.js +3 -3
  8. package/dist/development/lib/actions.js +10 -5
  9. package/dist/development/lib/components.js +50 -10
  10. package/dist/development/lib/context.d.ts +14 -5
  11. package/dist/development/lib/context.js +11 -3
  12. package/dist/development/lib/dom/dom.js +2 -2
  13. package/dist/development/lib/dom/lib.js +33 -36
  14. package/dist/development/lib/dom/server.d.ts +6 -1
  15. package/dist/development/lib/dom/server.js +40 -14
  16. package/dist/development/lib/dom/ssr/components.js +16 -24
  17. package/dist/development/lib/dom/ssr/data.js +1 -1
  18. package/dist/development/lib/dom/ssr/entry.d.ts +4 -0
  19. package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
  20. package/dist/development/lib/dom/ssr/fallback.js +1 -1
  21. package/dist/development/lib/dom/ssr/fog-of-war.js +34 -12
  22. package/dist/development/lib/dom/ssr/hydration.d.ts +3 -1
  23. package/dist/development/lib/dom/ssr/hydration.js +6 -4
  24. package/dist/development/lib/dom/ssr/invariant.js +1 -1
  25. package/dist/development/lib/dom/ssr/links.js +1 -1
  26. package/dist/development/lib/dom/ssr/markup.js +5 -2
  27. package/dist/development/lib/dom/ssr/routeModules.js +1 -1
  28. package/dist/development/lib/dom/ssr/routes-test-stub.js +1 -1
  29. package/dist/development/lib/dom/ssr/routes.js +1 -1
  30. package/dist/development/lib/dom/ssr/server.js +2 -2
  31. package/dist/development/lib/dom/ssr/single-fetch.js +13 -22
  32. package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
  33. package/dist/development/lib/dom-export/hydrated-router.js +2 -1
  34. package/dist/development/lib/errors.js +1 -1
  35. package/dist/development/lib/hooks.js +54 -46
  36. package/dist/development/lib/href.js +1 -1
  37. package/dist/development/lib/router/history.js +2 -2
  38. package/dist/development/lib/router/instrumentation.js +1 -1
  39. package/dist/development/lib/router/matcher-route-pattern.d.ts +2 -0
  40. package/dist/development/lib/router/matcher-route-pattern.js +216 -0
  41. package/dist/development/lib/router/matcher-route-pattern.preload.d.ts +20 -0
  42. package/dist/development/lib/router/matcher-route-pattern.preload.js +36 -0
  43. package/dist/development/lib/router/matcher.d.ts +2 -0
  44. package/dist/development/lib/router/matcher.js +29 -0
  45. package/dist/development/lib/router/navigation.js +45 -0
  46. package/dist/development/lib/router/router.d.ts +21 -7
  47. package/dist/development/lib/router/router.js +111 -82
  48. package/dist/development/lib/router/url.js +1 -1
  49. package/dist/development/lib/router/utils.d.ts +6 -1
  50. package/dist/development/lib/router/utils.js +15 -9
  51. package/dist/development/lib/rsc/browser.js +5 -1
  52. package/dist/development/lib/rsc/errorBoundaries.js +1 -1
  53. package/dist/development/lib/rsc/html-stream/browser.js +1 -1
  54. package/dist/development/lib/rsc/html-stream/server.js +3 -5
  55. package/dist/development/lib/rsc/route-modules.js +1 -1
  56. package/dist/development/lib/rsc/server.rsc.d.ts +7 -0
  57. package/dist/development/lib/rsc/server.ssr.js +26 -22
  58. package/dist/development/lib/server-runtime/cookies.js +2 -2
  59. package/dist/development/lib/server-runtime/crypto.js +2 -2
  60. package/dist/development/lib/server-runtime/data.js +1 -1
  61. package/dist/development/lib/server-runtime/dev.js +2 -2
  62. package/dist/development/lib/server-runtime/entry.js +1 -1
  63. package/dist/development/lib/server-runtime/errors.js +1 -1
  64. package/dist/development/lib/server-runtime/headers.js +1 -1
  65. package/dist/development/lib/server-runtime/invariant.js +1 -1
  66. package/dist/development/lib/server-runtime/mode.js +1 -1
  67. package/dist/development/lib/server-runtime/routeMatching.js +3 -4
  68. package/dist/development/lib/server-runtime/routes.js +1 -1
  69. package/dist/development/lib/server-runtime/server.js +8 -7
  70. package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
  71. package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
  72. package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
  73. package/dist/development/lib/server-runtime/sessions.js +1 -1
  74. package/dist/development/lib/server-runtime/single-fetch.js +2 -2
  75. package/dist/development/lib/server-runtime/urls.js +1 -1
  76. package/dist/development/lib/server-runtime/warnings.js +1 -1
  77. package/dist/development/lib/types/internal.js +1 -1
  78. package/dist/development/route-pattern.d.ts +3 -0
  79. package/dist/development/route-pattern.js +12 -0
  80. package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
  81. package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +4 -4
  82. package/dist/development/vendor/turbo-stream-v2/unflatten.js +1 -1
  83. package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
  84. package/dist/production/dom-export.js +1 -1
  85. package/dist/production/index-react-server-client.js +1 -1
  86. package/dist/production/index-react-server.d.ts +50 -48
  87. package/dist/production/index-react-server.js +96 -43
  88. package/dist/production/index.d.ts +2 -2
  89. package/dist/production/index.js +3 -3
  90. package/dist/production/lib/actions.js +10 -5
  91. package/dist/production/lib/components.js +50 -10
  92. package/dist/production/lib/context.d.ts +14 -5
  93. package/dist/production/lib/context.js +11 -3
  94. package/dist/production/lib/dom/dom.js +2 -2
  95. package/dist/production/lib/dom/lib.js +33 -36
  96. package/dist/production/lib/dom/server.d.ts +6 -1
  97. package/dist/production/lib/dom/server.js +40 -14
  98. package/dist/production/lib/dom/ssr/components.js +16 -24
  99. package/dist/production/lib/dom/ssr/data.js +1 -1
  100. package/dist/production/lib/dom/ssr/entry.d.ts +4 -0
  101. package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
  102. package/dist/production/lib/dom/ssr/fallback.js +1 -1
  103. package/dist/production/lib/dom/ssr/fog-of-war.js +34 -12
  104. package/dist/production/lib/dom/ssr/hydration.d.ts +3 -1
  105. package/dist/production/lib/dom/ssr/hydration.js +6 -4
  106. package/dist/production/lib/dom/ssr/invariant.js +1 -1
  107. package/dist/production/lib/dom/ssr/links.js +1 -1
  108. package/dist/production/lib/dom/ssr/markup.js +5 -2
  109. package/dist/production/lib/dom/ssr/routeModules.js +1 -1
  110. package/dist/production/lib/dom/ssr/routes-test-stub.js +1 -1
  111. package/dist/production/lib/dom/ssr/routes.js +1 -1
  112. package/dist/production/lib/dom/ssr/server.js +2 -2
  113. package/dist/production/lib/dom/ssr/single-fetch.js +13 -22
  114. package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
  115. package/dist/production/lib/dom-export/hydrated-router.js +2 -1
  116. package/dist/production/lib/errors.js +1 -1
  117. package/dist/production/lib/hooks.js +54 -46
  118. package/dist/production/lib/href.js +1 -1
  119. package/dist/production/lib/router/history.js +2 -2
  120. package/dist/production/lib/router/instrumentation.js +1 -1
  121. package/dist/production/lib/router/matcher-route-pattern.d.ts +2 -0
  122. package/dist/production/lib/router/matcher-route-pattern.js +216 -0
  123. package/dist/production/lib/router/matcher-route-pattern.preload.d.ts +20 -0
  124. package/dist/production/lib/router/matcher-route-pattern.preload.js +36 -0
  125. package/dist/production/lib/router/matcher.d.ts +2 -0
  126. package/dist/production/lib/router/matcher.js +29 -0
  127. package/dist/production/lib/router/navigation.js +45 -0
  128. package/dist/production/lib/router/router.d.ts +21 -7
  129. package/dist/production/lib/router/router.js +111 -82
  130. package/dist/production/lib/router/url.js +1 -1
  131. package/dist/production/lib/router/utils.d.ts +6 -1
  132. package/dist/production/lib/router/utils.js +15 -9
  133. package/dist/production/lib/rsc/browser.js +5 -1
  134. package/dist/production/lib/rsc/errorBoundaries.js +1 -1
  135. package/dist/production/lib/rsc/html-stream/browser.js +1 -1
  136. package/dist/production/lib/rsc/html-stream/server.js +3 -5
  137. package/dist/production/lib/rsc/route-modules.js +1 -1
  138. package/dist/production/lib/rsc/server.rsc.d.ts +7 -0
  139. package/dist/production/lib/rsc/server.ssr.js +26 -22
  140. package/dist/production/lib/server-runtime/cookies.js +2 -2
  141. package/dist/production/lib/server-runtime/crypto.js +2 -2
  142. package/dist/production/lib/server-runtime/data.js +1 -1
  143. package/dist/production/lib/server-runtime/dev.js +2 -2
  144. package/dist/production/lib/server-runtime/entry.js +1 -1
  145. package/dist/production/lib/server-runtime/errors.js +1 -1
  146. package/dist/production/lib/server-runtime/headers.js +1 -1
  147. package/dist/production/lib/server-runtime/invariant.js +1 -1
  148. package/dist/production/lib/server-runtime/mode.js +1 -1
  149. package/dist/production/lib/server-runtime/routeMatching.js +3 -4
  150. package/dist/production/lib/server-runtime/routes.js +1 -1
  151. package/dist/production/lib/server-runtime/server.js +8 -7
  152. package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
  153. package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
  154. package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
  155. package/dist/production/lib/server-runtime/sessions.js +1 -1
  156. package/dist/production/lib/server-runtime/single-fetch.js +2 -2
  157. package/dist/production/lib/server-runtime/urls.js +1 -1
  158. package/dist/production/lib/server-runtime/warnings.js +1 -1
  159. package/dist/production/lib/types/internal.js +1 -1
  160. package/dist/production/route-pattern.d.ts +3 -0
  161. package/dist/production/route-pattern.js +12 -0
  162. package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
  163. package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +4 -4
  164. package/dist/production/vendor/turbo-stream-v2/unflatten.js +1 -1
  165. package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
  166. package/docs/how-to/fetchers.md +6 -1
  167. package/docs/how-to/middleware.md +3 -1
  168. package/docs/how-to/optimize-revalidation.md +178 -5
  169. package/docs/how-to/react-server-components.md +26 -3
  170. package/docs/how-to/resource-routes.md +3 -0
  171. package/docs/start/data/actions.md +2 -1
  172. package/docs/start/data/route-object.md +21 -6
  173. package/docs/start/framework/actions.md +4 -2
  174. package/docs/start/framework/route-module.md +32 -5
  175. package/docs/upgrading/future.md +68 -0
  176. package/package.json +11 -1
@@ -1,7 +1,7 @@
1
1
 
2
2
  import { Path } from "../../router/history.js";
3
3
  import { DataRouteObject } from "../../router/utils.js";
4
- import { HydrationState, Router } from "../../router/router.js";
4
+ import { FutureConfig, HydrationState, Router } from "../../router/router.js";
5
5
  import { ClientLoaderFunction } from "./routeModules.js";
6
6
 
7
7
  //#region lib/dom/ssr/hydration.d.ts
@@ -11,6 +11,7 @@ declare function getHydrationData({
11
11
  getRouteInfo,
12
12
  location,
13
13
  basename,
14
+ future,
14
15
  isSpaMode
15
16
  }: {
16
17
  state: {
@@ -26,6 +27,7 @@ declare function getHydrationData({
26
27
  };
27
28
  location: Path;
28
29
  basename: string | undefined;
30
+ future: FutureConfig;
29
31
  isSpaMode: boolean;
30
32
  }): HydrationState;
31
33
  //#endregion
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,15 +8,17 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { matchRoutes } from "../../router/utils.js";
11
+ import { createDataRouteMatcher } from "../../router/router.js";
12
12
  import { shouldHydrateRouteLoader } from "./routes.js";
13
13
  //#region lib/dom/ssr/hydration.tsx
14
- function getHydrationData({ state, routes, getRouteInfo, location, basename, isSpaMode }) {
14
+ function getHydrationData({ state, routes, getRouteInfo, location, basename, future, isSpaMode }) {
15
15
  let hydrationData = {
16
16
  ...state,
17
17
  loaderData: { ...state.loaderData }
18
18
  };
19
- let initialMatches = matchRoutes(routes, location, basename);
19
+ let dataRouteMatcher = createDataRouteMatcher(future, basename || "/");
20
+ dataRouteMatcher.update(routes);
21
+ let initialMatches = dataRouteMatcher.match(location);
20
22
  if (initialMatches) for (let match of initialMatches) {
21
23
  let routeId = match.route.id;
22
24
  let routeInfo = getRouteInfo(routeId);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -20,5 +20,8 @@ const ESCAPE_REGEX = /[&><\u2028\u2029]/g;
20
20
  function escapeHtml(html) {
21
21
  return html.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
22
22
  }
23
+ function escapeAttribute(value) {
24
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
25
+ }
23
26
  //#endregion
24
- export { escapeHtml };
27
+ export { escapeAttribute, escapeHtml };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -40,7 +40,7 @@ function ServerRouter({ context, url, nonce }) {
40
40
  let manifestRoute = context.manifest.routes[routeId];
41
41
  if (route && manifestRoute && shouldHydrateRouteLoader(routeId, route.clientLoader, manifestRoute.hasLoader, context.isSpaMode) && (route.HydrateFallback || !manifestRoute.hasLoader)) delete context.staticHandlerContext.loaderData[routeId];
42
42
  }
43
- let router = createStaticRouter(routes, context.staticHandlerContext, { branches: context.branches });
43
+ let router = createStaticRouter(routes, context.staticHandlerContext, { future: context.future });
44
44
  return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, /* @__PURE__ */ React$1.createElement(FrameworkContext.Provider, { value: {
45
45
  manifest,
46
46
  routeModules,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -101,25 +101,16 @@ async function singleFetchActionStrategy(args, fetchAndDecode) {
101
101
  async function nonSsrStrategy(args, getRouteInfo, fetchAndDecode) {
102
102
  let matchesToLoad = args.matches.filter((m) => m.shouldCallHandler());
103
103
  let results = {};
104
- await Promise.all(matchesToLoad.map((m) => m.resolve(async (handler) => {
105
- try {
104
+ await Promise.all(matchesToLoad.map(async (m) => {
105
+ let routeId = m.route.id;
106
+ results[routeId] = await m.resolve(async (handler) => {
106
107
  let { hasClientLoader } = getRouteInfo(m);
107
- let routeId = m.route.id;
108
- let result = hasClientLoader ? await handler(async () => {
108
+ return hasClientLoader ? handler(async () => {
109
109
  let { data } = await fetchAndDecode(args, [routeId]);
110
110
  return unwrapSingleFetchResult(data, routeId);
111
- }) : await handler();
112
- results[m.route.id] = {
113
- type: "data",
114
- result
115
- };
116
- } catch (e) {
117
- results[m.route.id] = {
118
- type: "error",
119
- result: e
120
- };
121
- }
122
- })));
111
+ }) : handler();
112
+ });
113
+ }));
123
114
  return results;
124
115
  }
125
116
  async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, fetchAndDecode, ssr, shouldAllowOptOut = () => true) {
@@ -205,7 +196,7 @@ async function bubbleMiddlewareErrors(singleFetchPromise, matches, routesParams,
205
196
  if (middlewareError !== void 0) Array.from(routesParams.values()).forEach((routeId) => {
206
197
  if (results[routeId].result instanceof SingleFetchNoResultError) results[routeId].result = middlewareError;
207
198
  });
208
- } catch (e) {}
199
+ } catch {}
209
200
  }
210
201
  async function singleFetchLoaderFetcherStrategy(args, fetchAndDecode) {
211
202
  let fetcherMatch = args.matches.find((m) => m.shouldCallHandler());
@@ -277,8 +268,8 @@ async function fetchAndDecodeViaTurboStream(args, targetRoutes) {
277
268
  status: res.status,
278
269
  data
279
270
  };
280
- } catch (e) {
281
- throw new Error("Unable to decode turbo-stream response");
271
+ } catch (cause) {
272
+ throw new Error("Unable to decode turbo-stream response", { cause });
282
273
  }
283
274
  }
284
275
  function decodeViaTurboStream(body, global) {
@@ -326,13 +317,13 @@ function createDeferred() {
326
317
  res(val);
327
318
  try {
328
319
  await promise;
329
- } catch (e) {}
320
+ } catch {}
330
321
  };
331
322
  reject = async (error) => {
332
323
  rej(error);
333
324
  try {
334
325
  await promise;
335
- } catch (e) {}
326
+ } catch {}
336
327
  };
337
328
  });
338
329
  return {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -67,6 +67,7 @@ function createHydratedRouter({ getContext, instrumentations }) {
67
67
  }),
68
68
  location: window.location,
69
69
  basename: window.__reactRouterContext?.basename,
70
+ future: ssrInfo.context.future,
70
71
  isSpaMode: ssrInfo.context.isSpaMode
71
72
  });
72
73
  if (window.history.state && window.history.state.masked) window.history.replaceState({
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,10 +8,11 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { invariant, parsePath, warning } from "./router/history.js";
11
+ import { createPath, invariant, parsePath, warning } from "./router/history.js";
12
12
  import { convertRouteMatchToUiMatch, decodePath, getResolveToMatches, getRoutePattern, isBrowser, isRouteErrorResponse, joinPaths, matchPath, matchRoutes, parseToInfo, resolveTo, stripBasename } from "./router/utils.js";
13
+ import { getNavigatorCurrentUrl, validateNavigationTarget } from "./router/navigation.js";
13
14
  import { IDLE_BLOCKER, hasInvalidProtocol } from "./router/router.js";
14
- import { AwaitContext, DataRouterContext, DataRouterStateContext, LocationContext, NavigationContext, RSCRouterContext, RouteContext, RouteErrorContext } from "./context.js";
15
+ import { AwaitContext, DataRouterContext, DataRouterDataContext, DataRouterNavigationContext, DataRouterStateContext, FetchersContext, IsDataRouteContext, LocationContext, NavigationContext, RSCRouterContext, RouteContext, RouteErrorContext, RouteIdContext } from "./context.js";
15
16
  import { decodeRedirectErrorDigest, decodeRouteErrorResponseDigest } from "./errors.js";
16
17
  import * as React$1 from "react";
17
18
  //#region lib/hooks.tsx
@@ -268,8 +269,7 @@ const navigateEffectWarning = "You should call navigate() in a React.useEffect()
268
269
  * @returns A navigate function for programmatic navigation
269
270
  */
270
271
  function useNavigate() {
271
- let { isDataRoute } = React$1.useContext(RouteContext);
272
- return isDataRoute ? useNavigateStable() : useNavigateUnstable();
272
+ return React$1.useContext(IsDataRouteContext) ? useNavigateStable() : useNavigateUnstable();
273
273
  }
274
274
  function useNavigateUnstable() {
275
275
  invariant(useInRouterContext(), `useNavigate() may be used only in the context of a <Router> component.`);
@@ -291,6 +291,7 @@ function useNavigateUnstable() {
291
291
  }
292
292
  let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path");
293
293
  if (dataRouterContext == null && basename !== "/") path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
294
+ validateNavigationTarget(typeof to === "string" ? to : createPath(to), navigator.createHref(path), getNavigatorCurrentUrl(navigator), "reject");
294
295
  (!!options.replace ? navigator.replace : navigator.push)(path, options.state, options);
295
296
  }, [
296
297
  basename,
@@ -601,7 +602,10 @@ function useRoutesImpl(routes, locationArg, dataRouterOpts) {
601
602
  let parentSegments = parentPathnameBase.replace(/^\//, "").split("/");
602
603
  remainingPathname = "/" + pathname.replace(/^\//, "").split("/").slice(parentSegments.length).join("/");
603
604
  }
604
- let matches = dataRouterOpts && dataRouterOpts.state.matches.length ? dataRouterOpts.state.matches.map((m) => Object.assign(m, { route: dataRouterOpts.manifest[m.route.id] || m.route })) : matchRoutes(routes, { pathname: remainingPathname });
605
+ let matches;
606
+ if (dataRouterOpts) if (dataRouterOpts.state.matches.length) matches = dataRouterOpts.state.matches.map((m) => Object.assign(m, { route: dataRouterOpts.manifest[m.route.id] || m.route }));
607
+ else matches = dataRouterOpts.router.match(dataRouterOpts.state.location);
608
+ else matches = matchRoutes(routes, { pathname: remainingPathname });
605
609
  warning(parentRoute || matches != null, `No routes matched location "${location.pathname}${location.search}${location.hash}" `);
606
610
  warning(matches == null || matches[matches.length - 1].route.element !== void 0 || matches[matches.length - 1].route.Component !== void 0 || matches[matches.length - 1].route.lazy !== void 0, `Matched leaf route at location "${location.pathname}${location.search}${location.hash}" does not have an element or Component. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.`);
607
611
  let renderedMatches = _renderMatches(matches && matches.map((match) => Object.assign({}, match, {
@@ -677,17 +681,17 @@ var RenderErrorBoundary = class extends React$1.Component {
677
681
  const decoded = decodeRouteErrorResponseDigest(error.digest);
678
682
  if (decoded) error = decoded;
679
683
  }
680
- let result = error !== void 0 ? /* @__PURE__ */ React$1.createElement(RouteContext.Provider, { value: this.props.routeContext }, /* @__PURE__ */ React$1.createElement(RouteErrorContext.Provider, {
684
+ let result = error !== void 0 ? /* @__PURE__ */ React$1.createElement(RouteContext.Provider, { value: this.props.routeContext }, /* @__PURE__ */ React$1.createElement(IsDataRouteContext.Provider, { value: this.props.routeContext.isDataRoute }, /* @__PURE__ */ React$1.createElement(RouteIdContext.Provider, { value: this.props.routeContext.matches[this.props.routeContext.matches.length - 1]?.route.id }, /* @__PURE__ */ React$1.createElement(RouteErrorContext.Provider, {
681
685
  value: error,
682
686
  children: this.props.component
683
- })) : this.props.children;
687
+ })))) : this.props.children;
684
688
  if (this.context) return /* @__PURE__ */ React$1.createElement(RSCErrorHandler, { error }, result);
685
689
  return result;
686
690
  }
687
691
  };
688
692
  const errorRedirectHandledMap = /* @__PURE__ */ new WeakMap();
689
693
  function RSCErrorHandler({ children, error }) {
690
- let { basename } = React$1.useContext(NavigationContext);
694
+ let { basename, navigator } = React$1.useContext(NavigationContext);
691
695
  if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
692
696
  let redirect = decodeRedirectErrorDigest(error.digest);
693
697
  if (redirect) {
@@ -695,6 +699,7 @@ function RSCErrorHandler({ children, error }) {
695
699
  if (existingRedirect) throw existingRedirect;
696
700
  let parsed = parseToInfo(redirect.location, basename);
697
701
  let target = parsed.absoluteURL || parsed.to;
702
+ validateNavigationTarget(redirect.location, target, getNavigatorCurrentUrl(navigator), "allow-explicit");
698
703
  if (hasInvalidProtocol(target)) throw new Error("Invalid redirect location");
699
704
  if (isBrowser && !errorRedirectHandledMap.get(error)) if (parsed.isExternal || redirect.reloadDocument) window.location.href = target;
700
705
  else {
@@ -713,7 +718,7 @@ function RSCErrorHandler({ children, error }) {
713
718
  function RenderedRoute({ routeContext, match, children }) {
714
719
  let dataRouterContext = React$1.useContext(DataRouterContext);
715
720
  if (dataRouterContext && dataRouterContext.static && dataRouterContext.staticContext && (match.route.errorElement || match.route.ErrorBoundary)) dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id;
716
- return /* @__PURE__ */ React$1.createElement(RouteContext.Provider, { value: routeContext }, children);
721
+ return /* @__PURE__ */ React$1.createElement(RouteContext.Provider, { value: routeContext }, /* @__PURE__ */ React$1.createElement(IsDataRouteContext.Provider, { value: routeContext.isDataRoute }, /* @__PURE__ */ React$1.createElement(RouteIdContext.Provider, { value: match.route.id }, children)));
717
722
  }
718
723
  function _renderMatches(matches, parentMatches = [], dataRouterOpts) {
719
724
  let dataRouterState = dataRouterOpts?.state;
@@ -823,25 +828,25 @@ function useDataRouterState(hookName) {
823
828
  invariant(state, getDataRouterConsoleError(hookName));
824
829
  return state;
825
830
  }
826
- function useRouteContext(hookName) {
827
- let route = React$1.useContext(RouteContext);
828
- invariant(route, getDataRouterConsoleError(hookName));
829
- return route;
831
+ function useDataRouterFetchers(hookName) {
832
+ let fetchers = React$1.useContext(FetchersContext);
833
+ invariant(fetchers, getDataRouterConsoleError(hookName));
834
+ return fetchers;
830
835
  }
831
- function useCurrentRouteId(hookName) {
832
- let route = useRouteContext(hookName);
833
- let thisRoute = route.matches[route.matches.length - 1];
834
- invariant(thisRoute.route.id, `${hookName} can only be used on routes that contain a unique "id"`);
835
- return thisRoute.route.id;
836
+ function useDataRouterData(hookName) {
837
+ let data = React$1.useContext(DataRouterDataContext);
838
+ invariant(data, getDataRouterConsoleError(hookName));
839
+ return data;
836
840
  }
837
- /**
838
- * Returns the ID for the nearest contextual route
839
- *
840
- * @category Hooks
841
- * @returns The ID of the nearest contextual route
842
- */
843
- function useRouteId() {
844
- return useCurrentRouteId("useRouteId");
841
+ function useDataRouterNavigation(hookName) {
842
+ let navigation = React$1.useContext(DataRouterNavigationContext);
843
+ invariant(navigation, getDataRouterConsoleError(hookName));
844
+ return navigation;
845
+ }
846
+ function useCurrentRouteId(hookName) {
847
+ let routeId = React$1.useContext(RouteIdContext);
848
+ invariant(routeId, `${hookName} can only be used on routes that contain a unique "id"`);
849
+ return routeId;
845
850
  }
846
851
  /**
847
852
  * Returns the current {@link Navigation}, defaulting to an "idle" navigation
@@ -866,11 +871,11 @@ function useRouteId() {
866
871
  * @returns The current {@link Navigation} object
867
872
  */
868
873
  function useNavigation() {
869
- let state = useDataRouterState("useNavigation");
874
+ let { navigation } = useDataRouterNavigation("useNavigation");
870
875
  return React$1.useMemo(() => {
871
- let { matches, historyAction, ...rest } = state.navigation;
876
+ let { matches, historyAction, ...rest } = navigation;
872
877
  return rest;
873
- }, [state.navigation]);
878
+ }, [navigation]);
874
879
  }
875
880
  /**
876
881
  * Revalidate the data on the page for reasons outside of normal data mutations
@@ -909,14 +914,14 @@ function useNavigation() {
909
914
  */
910
915
  function useRevalidator() {
911
916
  let dataRouterContext = useDataRouterContext("useRevalidator");
912
- let state = useDataRouterState("useRevalidator");
917
+ let { revalidation } = useDataRouterNavigation("useRevalidator");
913
918
  let revalidate = React$1.useCallback(async () => {
914
919
  await dataRouterContext.router.revalidate();
915
920
  }, [dataRouterContext.router]);
916
921
  return React$1.useMemo(() => ({
917
922
  revalidate,
918
- state: state.revalidation
919
- }), [revalidate, state.revalidation]);
923
+ state: revalidation
924
+ }), [revalidate, revalidation]);
920
925
  }
921
926
  /**
922
927
  * Returns the active route matches, useful for accessing `loaderData` for
@@ -953,7 +958,8 @@ function useRevalidator() {
953
958
  * @returns An array of {@link UIMatch | UI matches} for the current route hierarchy
954
959
  */
955
960
  function useMatches() {
956
- let { matches, loaderData } = useDataRouterState("useMatches");
961
+ let { matches } = useDataRouterState("useMatches");
962
+ let { loaderData } = useDataRouterData("useMatches");
957
963
  return React$1.useMemo(() => matches.map((m) => convertRouteMatchToUiMatch(m, loaderData)), [matches, loaderData]);
958
964
  }
959
965
  /**
@@ -980,9 +986,9 @@ function useMatches() {
980
986
  * @returns The data returned from the route's [`loader`](../../start/framework/route-module#loader) or [`clientLoader`](../../start/framework/route-module#clientloader) function
981
987
  */
982
988
  function useLoaderData() {
983
- let state = useDataRouterState("useLoaderData");
989
+ let data = useDataRouterData("useLoaderData");
984
990
  let routeId = useCurrentRouteId("useLoaderData");
985
- return state.loaderData[routeId];
991
+ return data.loaderData[routeId];
986
992
  }
987
993
  /**
988
994
  * Returns the [`loader`](../../start/framework/route-module#loader) data for a
@@ -1017,7 +1023,7 @@ function useLoaderData() {
1017
1023
  * function, or `undefined` if not found
1018
1024
  */
1019
1025
  function useRouteLoaderData(routeId) {
1020
- return useDataRouterState("useRouteLoaderData").loaderData[routeId];
1026
+ return useDataRouterData("useRouteLoaderData").loaderData[routeId];
1021
1027
  }
1022
1028
  /**
1023
1029
  * Returns the [`action`](../../start/framework/route-module#action) data from
@@ -1052,9 +1058,9 @@ function useRouteLoaderData(routeId) {
1052
1058
  * has been called
1053
1059
  */
1054
1060
  function useActionData() {
1055
- let state = useDataRouterState("useActionData");
1056
- let routeId = useCurrentRouteId("useLoaderData");
1057
- return state.actionData ? state.actionData[routeId] : void 0;
1061
+ let data = useDataRouterData("useActionData");
1062
+ let routeId = useCurrentRouteId("useActionData");
1063
+ return data.actionData ? data.actionData[routeId] : void 0;
1058
1064
  }
1059
1065
  /**
1060
1066
  * Accesses the error thrown during an
@@ -1078,10 +1084,10 @@ function useActionData() {
1078
1084
  */
1079
1085
  function useRouteError() {
1080
1086
  let error = React$1.useContext(RouteErrorContext);
1081
- let state = useDataRouterState("useRouteError");
1087
+ let data = useDataRouterData("useRouteError");
1082
1088
  let routeId = useCurrentRouteId("useRouteError");
1083
1089
  if (error !== void 0) return error;
1084
- return state.errors?.[routeId];
1090
+ return data.errors?.[routeId];
1085
1091
  }
1086
1092
  /**
1087
1093
  * Returns the resolved promise value from the closest {@link Await | `<Await>`}.
@@ -1306,12 +1312,13 @@ function useRoute(...args) {
1306
1312
  const currentRouteId = useCurrentRouteId("useRoute");
1307
1313
  const id = args[0] ?? currentRouteId;
1308
1314
  const state = useDataRouterState("useRoute");
1315
+ const data = useDataRouterData("useRoute");
1309
1316
  const route = state.matches.find(({ route }) => route.id === id);
1310
1317
  if (route === void 0) return void 0;
1311
1318
  return {
1312
1319
  handle: route.route.handle,
1313
- loaderData: state.loaderData[id],
1314
- actionData: state.actionData?.[id]
1320
+ loaderData: data.loaderData[id],
1321
+ actionData: data.actionData?.[id]
1315
1322
  };
1316
1323
  }
1317
1324
  function toRouterStateMatch(match) {
@@ -1365,7 +1372,8 @@ function toRouterStateMatch(match) {
1365
1372
  * @returns The current router state with `active` and `pending` variants
1366
1373
  */
1367
1374
  function useRouterState() {
1368
- let { location, historyAction: type, matches, navigation } = useDataRouterState("unstable_useRouterState");
1375
+ let { location, historyAction: type, matches } = useDataRouterState("unstable_useRouterState");
1376
+ let { navigation } = useDataRouterNavigation("unstable_useRouterState");
1369
1377
  let active = React$1.useMemo(() => ({
1370
1378
  type,
1371
1379
  location,
@@ -1412,4 +1420,4 @@ function useRouterState() {
1412
1420
  }), [active, pending]);
1413
1421
  }
1414
1422
  //#endregion
1415
- export { _renderMatches, useActionData, useAsyncError, useAsyncValue, useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRoute, useRouteError, useRouteId, useRouteLoaderData, useRouterState, useRoutes, useRoutesImpl };
1423
+ export { _renderMatches, useActionData, useAsyncError, useAsyncValue, useBlocker, useCurrentRouteId, useDataRouterContext, useDataRouterData, useDataRouterFetchers, useDataRouterState, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRoute, useRouteError, useRouteLoaderData, useRouterState, useRoutes, useRoutesImpl };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -193,7 +193,7 @@ function warning(cond, message) {
193
193
  if (typeof console !== "undefined") console.warn(message);
194
194
  try {
195
195
  throw new Error(message);
196
- } catch (e) {}
196
+ } catch {}
197
197
  }
198
198
  }
199
199
  function createKey() {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.3.0
2
+ * react-router v8.4.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *