react-router 8.1.0 → 8.3.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 (178) hide show
  1. package/CHANGELOG.md +83 -0
  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 +109 -19
  5. package/dist/development/index-react-server.js +176 -45
  6. package/dist/development/index.js +1 -1
  7. package/dist/development/lib/actions.js +1 -1
  8. package/dist/development/lib/components.js +1 -1
  9. package/dist/development/lib/context.js +1 -1
  10. package/dist/development/lib/dom/dom.d.ts +24 -24
  11. package/dist/development/lib/dom/dom.js +25 -25
  12. package/dist/development/lib/dom/lib.d.ts +2 -1
  13. package/dist/development/lib/dom/lib.js +5 -4
  14. package/dist/development/lib/dom/server.js +1 -1
  15. package/dist/development/lib/dom/ssr/components.js +1 -1
  16. package/dist/development/lib/dom/ssr/data.js +1 -1
  17. package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
  18. package/dist/development/lib/dom/ssr/fallback.js +1 -1
  19. package/dist/development/lib/dom/ssr/fog-of-war.js +26 -21
  20. package/dist/development/lib/dom/ssr/hydration.js +1 -1
  21. package/dist/development/lib/dom/ssr/invariant.js +1 -1
  22. package/dist/development/lib/dom/ssr/links.js +1 -1
  23. package/dist/development/lib/dom/ssr/markup.js +1 -1
  24. package/dist/development/lib/dom/ssr/routeModules.js +1 -1
  25. package/dist/development/lib/dom/ssr/routes-test-stub.d.ts +13 -0
  26. package/dist/development/lib/dom/ssr/routes-test-stub.js +14 -1
  27. package/dist/development/lib/dom/ssr/routes.js +1 -1
  28. package/dist/development/lib/dom/ssr/server.js +1 -1
  29. package/dist/development/lib/dom/ssr/single-fetch.js +1 -1
  30. package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
  31. package/dist/development/lib/dom-export/hydrated-router.js +1 -1
  32. package/dist/development/lib/errors.js +1 -1
  33. package/dist/development/lib/hooks.d.ts +33 -6
  34. package/dist/development/lib/hooks.js +34 -7
  35. package/dist/development/lib/href.d.ts +24 -8
  36. package/dist/development/lib/href.js +31 -11
  37. package/dist/development/lib/router/history.d.ts +6 -0
  38. package/dist/development/lib/router/history.js +7 -1
  39. package/dist/development/lib/router/instrumentation.js +1 -1
  40. package/dist/development/lib/router/router.js +2 -2
  41. package/dist/development/lib/router/url.js +1 -1
  42. package/dist/development/lib/router/utils.d.ts +12 -0
  43. package/dist/development/lib/router/utils.js +61 -5
  44. package/dist/development/lib/rsc/browser.js +34 -24
  45. package/dist/development/lib/rsc/errorBoundaries.js +1 -1
  46. package/dist/development/lib/rsc/html-stream/browser.js +1 -1
  47. package/dist/development/lib/rsc/html-stream/server.js +29 -10
  48. package/dist/development/lib/rsc/route-modules.js +1 -1
  49. package/dist/development/lib/rsc/server.rsc.d.ts +8 -3
  50. package/dist/development/lib/rsc/server.ssr.d.ts +29 -6
  51. package/dist/development/lib/rsc/server.ssr.js +27 -12
  52. package/dist/development/lib/server-runtime/cookies.d.ts +28 -2
  53. package/dist/development/lib/server-runtime/cookies.js +17 -3
  54. package/dist/development/lib/server-runtime/crypto.js +1 -1
  55. package/dist/development/lib/server-runtime/data.js +1 -1
  56. package/dist/development/lib/server-runtime/dev.js +1 -1
  57. package/dist/development/lib/server-runtime/entry.js +1 -1
  58. package/dist/development/lib/server-runtime/errors.js +1 -1
  59. package/dist/development/lib/server-runtime/headers.js +1 -1
  60. package/dist/development/lib/server-runtime/invariant.js +1 -1
  61. package/dist/development/lib/server-runtime/mode.js +1 -1
  62. package/dist/development/lib/server-runtime/routeMatching.js +1 -1
  63. package/dist/development/lib/server-runtime/routes.js +1 -1
  64. package/dist/development/lib/server-runtime/server.d.ts +12 -0
  65. package/dist/development/lib/server-runtime/server.js +13 -1
  66. package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
  67. package/dist/development/lib/server-runtime/sessions/cookieStorage.d.ts +8 -0
  68. package/dist/development/lib/server-runtime/sessions/cookieStorage.js +9 -1
  69. package/dist/development/lib/server-runtime/sessions/memoryStorage.d.ts +10 -4
  70. package/dist/development/lib/server-runtime/sessions/memoryStorage.js +12 -6
  71. package/dist/development/lib/server-runtime/sessions.d.ts +31 -2
  72. package/dist/development/lib/server-runtime/sessions.js +20 -3
  73. package/dist/development/lib/server-runtime/single-fetch.js +1 -1
  74. package/dist/development/lib/server-runtime/urls.js +1 -1
  75. package/dist/development/lib/server-runtime/warnings.js +1 -1
  76. package/dist/development/lib/types/internal.js +1 -1
  77. package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
  78. package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  79. package/dist/development/vendor/turbo-stream-v2/unflatten.js +1 -1
  80. package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
  81. package/dist/production/dom-export.js +1 -1
  82. package/dist/production/index-react-server-client.js +1 -1
  83. package/dist/production/index-react-server.d.ts +109 -19
  84. package/dist/production/index-react-server.js +176 -45
  85. package/dist/production/index.js +1 -1
  86. package/dist/production/lib/actions.js +1 -1
  87. package/dist/production/lib/components.js +1 -1
  88. package/dist/production/lib/context.js +1 -1
  89. package/dist/production/lib/dom/dom.d.ts +24 -24
  90. package/dist/production/lib/dom/dom.js +25 -25
  91. package/dist/production/lib/dom/lib.d.ts +2 -1
  92. package/dist/production/lib/dom/lib.js +5 -4
  93. package/dist/production/lib/dom/server.js +1 -1
  94. package/dist/production/lib/dom/ssr/components.js +1 -1
  95. package/dist/production/lib/dom/ssr/data.js +1 -1
  96. package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
  97. package/dist/production/lib/dom/ssr/fallback.js +1 -1
  98. package/dist/production/lib/dom/ssr/fog-of-war.js +26 -21
  99. package/dist/production/lib/dom/ssr/hydration.js +1 -1
  100. package/dist/production/lib/dom/ssr/invariant.js +1 -1
  101. package/dist/production/lib/dom/ssr/links.js +1 -1
  102. package/dist/production/lib/dom/ssr/markup.js +1 -1
  103. package/dist/production/lib/dom/ssr/routeModules.js +1 -1
  104. package/dist/production/lib/dom/ssr/routes-test-stub.d.ts +13 -0
  105. package/dist/production/lib/dom/ssr/routes-test-stub.js +14 -1
  106. package/dist/production/lib/dom/ssr/routes.js +1 -1
  107. package/dist/production/lib/dom/ssr/server.js +1 -1
  108. package/dist/production/lib/dom/ssr/single-fetch.js +1 -1
  109. package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
  110. package/dist/production/lib/dom-export/hydrated-router.js +1 -1
  111. package/dist/production/lib/errors.js +1 -1
  112. package/dist/production/lib/hooks.d.ts +33 -6
  113. package/dist/production/lib/hooks.js +34 -7
  114. package/dist/production/lib/href.d.ts +24 -8
  115. package/dist/production/lib/href.js +31 -11
  116. package/dist/production/lib/router/history.d.ts +6 -0
  117. package/dist/production/lib/router/history.js +7 -1
  118. package/dist/production/lib/router/instrumentation.js +1 -1
  119. package/dist/production/lib/router/router.js +2 -2
  120. package/dist/production/lib/router/url.js +1 -1
  121. package/dist/production/lib/router/utils.d.ts +12 -0
  122. package/dist/production/lib/router/utils.js +61 -5
  123. package/dist/production/lib/rsc/browser.js +34 -24
  124. package/dist/production/lib/rsc/errorBoundaries.js +1 -1
  125. package/dist/production/lib/rsc/html-stream/browser.js +1 -1
  126. package/dist/production/lib/rsc/html-stream/server.js +29 -10
  127. package/dist/production/lib/rsc/route-modules.js +1 -1
  128. package/dist/production/lib/rsc/server.rsc.d.ts +8 -3
  129. package/dist/production/lib/rsc/server.ssr.d.ts +29 -6
  130. package/dist/production/lib/rsc/server.ssr.js +27 -12
  131. package/dist/production/lib/server-runtime/cookies.d.ts +28 -2
  132. package/dist/production/lib/server-runtime/cookies.js +17 -3
  133. package/dist/production/lib/server-runtime/crypto.js +1 -1
  134. package/dist/production/lib/server-runtime/data.js +1 -1
  135. package/dist/production/lib/server-runtime/dev.js +1 -1
  136. package/dist/production/lib/server-runtime/entry.js +1 -1
  137. package/dist/production/lib/server-runtime/errors.js +1 -1
  138. package/dist/production/lib/server-runtime/headers.js +1 -1
  139. package/dist/production/lib/server-runtime/invariant.js +1 -1
  140. package/dist/production/lib/server-runtime/mode.js +1 -1
  141. package/dist/production/lib/server-runtime/routeMatching.js +1 -1
  142. package/dist/production/lib/server-runtime/routes.js +1 -1
  143. package/dist/production/lib/server-runtime/server.d.ts +12 -0
  144. package/dist/production/lib/server-runtime/server.js +13 -1
  145. package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
  146. package/dist/production/lib/server-runtime/sessions/cookieStorage.d.ts +8 -0
  147. package/dist/production/lib/server-runtime/sessions/cookieStorage.js +9 -1
  148. package/dist/production/lib/server-runtime/sessions/memoryStorage.d.ts +10 -4
  149. package/dist/production/lib/server-runtime/sessions/memoryStorage.js +12 -6
  150. package/dist/production/lib/server-runtime/sessions.d.ts +31 -2
  151. package/dist/production/lib/server-runtime/sessions.js +20 -3
  152. package/dist/production/lib/server-runtime/single-fetch.js +1 -1
  153. package/dist/production/lib/server-runtime/urls.js +1 -1
  154. package/dist/production/lib/server-runtime/warnings.js +1 -1
  155. package/dist/production/lib/types/internal.js +1 -1
  156. package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
  157. package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  158. package/dist/production/vendor/turbo-stream-v2/unflatten.js +1 -1
  159. package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
  160. package/docs/explanation/hot-module-replacement.md +1 -1
  161. package/docs/explanation/sessions-and-cookies.md +13 -13
  162. package/docs/explanation/state-management.md +2 -2
  163. package/docs/how-to/data-strategy.md +1 -1
  164. package/docs/how-to/presets.md +2 -2
  165. package/docs/how-to/react-server-components.md +53 -1
  166. package/docs/how-to/security.md +8 -1
  167. package/docs/how-to/server-bundles.md +2 -2
  168. package/docs/start/data/route-object.md +2 -2
  169. package/docs/start/data/routing.md +1 -1
  170. package/docs/start/framework/deploying.md +4 -0
  171. package/docs/start/framework/pending-ui.md +1 -1
  172. package/docs/start/framework/route-module.md +8 -8
  173. package/docs/start/framework/routing.md +1 -1
  174. package/docs/upgrading/component-routes.md +1 -1
  175. package/docs/upgrading/future.md +33 -0
  176. package/docs/upgrading/router-provider.md +5 -5
  177. package/docs/upgrading/v7.md +39 -22
  178. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -110,6 +110,29 @@ function getManifestPath(_manifestPath, basename) {
110
110
  return basename == null ? manifestPath : joinPaths([basename, manifestPath]);
111
111
  }
112
112
  const MANIFEST_VERSION_STORAGE_KEY = "react-router-manifest-version";
113
+ async function handleClientVersionMismatch(needsReload, version, errorReloadPath) {
114
+ if (!needsReload) {
115
+ try {
116
+ sessionStorage.removeItem(MANIFEST_VERSION_STORAGE_KEY);
117
+ } catch {}
118
+ return false;
119
+ }
120
+ if (!errorReloadPath) {
121
+ console.warn("Detected a manifest version mismatch during eager route discovery. The next navigation/fetch to an undiscovered route will result in a new document navigation to sync up with the latest manifest.");
122
+ return true;
123
+ }
124
+ try {
125
+ if (sessionStorage.getItem(MANIFEST_VERSION_STORAGE_KEY) === version) {
126
+ console.error("Unable to discover routes due to manifest version mismatch.");
127
+ return true;
128
+ }
129
+ sessionStorage.setItem(MANIFEST_VERSION_STORAGE_KEY, version);
130
+ } catch {}
131
+ window.location.href = errorReloadPath;
132
+ console.warn("Detected manifest version mismatch, reloading...");
133
+ await new Promise(() => {});
134
+ return true;
135
+ }
113
136
  async function fetchAndApplyManifestPatches(paths, errorReloadPath, manifest, routeModules, ssr, isSpaMode, basename, manifestPath, patchRoutes, signal) {
114
137
  paths = getPathsWithAncestors(paths);
115
138
  const searchParams = new URLSearchParams();
@@ -125,25 +148,7 @@ async function fetchAndApplyManifestPatches(paths, errorReloadPath, manifest, ro
125
148
  try {
126
149
  let res = await fetch(url, { signal });
127
150
  if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
128
- else if (res.status === 204 && res.headers.has("X-Remix-Reload-Document")) {
129
- if (!errorReloadPath) {
130
- console.warn("Detected a manifest version mismatch during eager route discovery. The next navigation/fetch to an undiscovered route will result in a new document navigation to sync up with the latest manifest.");
131
- return;
132
- }
133
- try {
134
- if (sessionStorage.getItem(MANIFEST_VERSION_STORAGE_KEY) === manifest.version) {
135
- console.error("Unable to discover routes due to manifest version mismatch.");
136
- return;
137
- }
138
- sessionStorage.setItem(MANIFEST_VERSION_STORAGE_KEY, manifest.version);
139
- } catch {}
140
- window.location.href = errorReloadPath;
141
- console.warn("Detected manifest version mismatch, reloading...");
142
- await new Promise(() => {});
143
- } else if (res.status >= 400) throw new Error(await res.text());
144
- try {
145
- sessionStorage.removeItem(MANIFEST_VERSION_STORAGE_KEY);
146
- } catch {}
151
+ if (await handleClientVersionMismatch(res.status === 204 && res.headers.has("X-Remix-Reload-Document"), manifest.version, errorReloadPath)) return;
147
152
  serverPatches = await res.json();
148
153
  } catch (e) {
149
154
  if (signal?.aborted) return;
@@ -177,4 +182,4 @@ function debounce(callback, wait) {
177
182
  };
178
183
  }
179
184
  //#endregion
180
- export { URL_LIMIT, getManifestPath, getPartialManifest, getPatchRoutesOnNavigationFunction, getPathsWithAncestors, isFogOfWarEnabled, useFogOFWarDiscovery };
185
+ export { URL_LIMIT, getManifestPath, getPartialManifest, getPatchRoutesOnNavigationFunction, getPathsWithAncestors, handleClientVersionMismatch, isFogOfWarEnabled, useFogOFWarDiscovery };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -50,7 +50,20 @@ interface RoutesTestStubProps {
50
50
  future?: Partial<FutureConfig>;
51
51
  }
52
52
  /**
53
+ * Creates a React component that renders the provided routes in a test-friendly
54
+ * React Router context.
55
+ *
56
+ * Use this to unit test components that rely on router context, such as
57
+ * `loaderData`, `actionData`, and route matches.
58
+ *
59
+ * @public
53
60
  * @category Utils
61
+ * @mode framework
62
+ * @mode data
63
+ * @param routes The route objects to render in the test router.
64
+ * @param _context An optional {@link RouterContextProvider} for supplying
65
+ * application context values to route middleware, loaders, and actions.
66
+ * @returns A React component that renders the test router.
54
67
  */
55
68
  declare function createRoutesStub(routes: StubRouteObject[], _context?: RouterContextProvider): ({
56
69
  initialEntries,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -14,7 +14,20 @@ import { FrameworkContext } from "./components.js";
14
14
  import * as React$1 from "react";
15
15
  //#region lib/dom/ssr/routes-test-stub.tsx
16
16
  /**
17
+ * Creates a React component that renders the provided routes in a test-friendly
18
+ * React Router context.
19
+ *
20
+ * Use this to unit test components that rely on router context, such as
21
+ * `loaderData`, `actionData`, and route matches.
22
+ *
23
+ * @public
17
24
  * @category Utils
25
+ * @mode framework
26
+ * @mode data
27
+ * @param routes The route objects to render in the test router.
28
+ * @param _context An optional {@link RouterContextProvider} for supplying
29
+ * application context values to route middleware, loaders, and actions.
30
+ * @returns A React component that renders the test router.
18
31
  */
19
32
  function createRoutesStub(routes, _context) {
20
33
  return function RoutesTestStub({ initialEntries, initialIndex, hydrationData, future }) {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -143,12 +143,16 @@ interface NavigateFunction {
143
143
  * All properties are optional.
144
144
  *
145
145
  * ```tsx
146
- * navigate({
147
- * pathname: "/some/route",
148
- * search: "?search=param",
149
- * hash: "#hash",
150
- * state: { some: "state" },
151
- * });
146
+ * navigate(
147
+ * {
148
+ * pathname: "/some/route",
149
+ * search: "?search=param",
150
+ * hash: "#hash",
151
+ * },
152
+ * {
153
+ * state: { some: "state" },
154
+ * },
155
+ * );
152
156
  * ```
153
157
  *
154
158
  * If you use `state`, that will be available on the {@link Location} object on
@@ -576,6 +580,29 @@ declare function useRevalidator(): {
576
580
  * parent/child routes or the route [`handle`](../../start/framework/route-module#handle)
577
581
  * property
578
582
  *
583
+ * Pairing the route `handle` with `useMatches` gets very powerful since you can put
584
+ * whatever you want on a route handle and have access to `useMatches` anywhere.
585
+ * Please see the [handle](../../how-to/using-handle) documentation for an example
586
+ * of breadcrumbs via `useMatches`/`handle`.
587
+ *
588
+ * ```tsx
589
+ * import { useMatches } from "react-router";
590
+ *
591
+ * function SomeComponent() {
592
+ * const matches = useMatches();
593
+ * // matches[i].id // route id
594
+ * // matches[i].pathname // the portion of the URL the route matched
595
+ * // matches[i].params // the parsed params from the URL
596
+ * // matches[i].loaderData // the data from the loader
597
+ * // matches[i].handle // the route handle with any app specific data
598
+ * }
599
+ * ```
600
+ *
601
+ * <docs-info>useMatches only works with a data router like `createBrowserRouter`,
602
+ * since they know the full route tree up front and can provide all of the current
603
+ * matches. Additionally, `useMatches` will not match down into any descendant route
604
+ * trees since the router isn't aware of the descendant routes.</docs-info>
605
+ *
579
606
  * @public
580
607
  * @category Hooks
581
608
  * @mode framework
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -162,12 +162,16 @@ const navigateEffectWarning = "You should call navigate() in a React.useEffect()
162
162
  * All properties are optional.
163
163
  *
164
164
  * ```tsx
165
- * navigate({
166
- * pathname: "/some/route",
167
- * search: "?search=param",
168
- * hash: "#hash",
169
- * state: { some: "state" },
170
- * });
165
+ * navigate(
166
+ * {
167
+ * pathname: "/some/route",
168
+ * search: "?search=param",
169
+ * hash: "#hash",
170
+ * },
171
+ * {
172
+ * state: { some: "state" },
173
+ * },
174
+ * );
171
175
  * ```
172
176
  *
173
177
  * If you use `state`, that will be available on the {@link Location} object on
@@ -919,6 +923,29 @@ function useRevalidator() {
919
923
  * parent/child routes or the route [`handle`](../../start/framework/route-module#handle)
920
924
  * property
921
925
  *
926
+ * Pairing the route `handle` with `useMatches` gets very powerful since you can put
927
+ * whatever you want on a route handle and have access to `useMatches` anywhere.
928
+ * Please see the [handle](../../how-to/using-handle) documentation for an example
929
+ * of breadcrumbs via `useMatches`/`handle`.
930
+ *
931
+ * ```tsx
932
+ * import { useMatches } from "react-router";
933
+ *
934
+ * function SomeComponent() {
935
+ * const matches = useMatches();
936
+ * // matches[i].id // route id
937
+ * // matches[i].pathname // the portion of the URL the route matched
938
+ * // matches[i].params // the parsed params from the URL
939
+ * // matches[i].loaderData // the data from the loader
940
+ * // matches[i].handle // the route handle with any app specific data
941
+ * }
942
+ * ```
943
+ *
944
+ * <docs-info>useMatches only works with a data router like `createBrowserRouter`,
945
+ * since they know the full route tree up front and can provide all of the current
946
+ * matches. Additionally, `useMatches` will not match down into any descendant route
947
+ * trees since the router isn't aware of the descendant routes.</docs-info>
948
+ *
922
949
  * @public
923
950
  * @category Hooks
924
951
  * @mode framework
@@ -6,14 +6,30 @@ import { Pages } from "./types/register.js";
6
6
  type Args = { [K in keyof Pages]: ToArgs<Pages[K]["params"]> };
7
7
  type ToArgs<Params extends Record<string, string | undefined>> = Equal<Params, {}> extends true ? [] : Partial<Params> extends Params ? [Params] | [] : [Params];
8
8
  /**
9
- Returns a resolved URL path for the specified route.
10
-
11
- ```tsx
12
- const h = href("/:lang?/about", { lang: "en" })
13
- // -> `/en/about`
14
-
15
- <Link to={href("/products/:id", { id: "abc123" })} />
16
- ```
9
+ * Returns a resolved URL path for the specified route.
10
+ *
11
+ * Param values are percent-encoded for use in a path segment: characters that
12
+ * would change the URL structure (`/`, `?`, `#`, `%`, whitespace, non-ASCII)
13
+ * are escaped, while characters that RFC 3986 allows literally in a path
14
+ * segment (`$ & + , ; = : @`) are kept as-is. Note this differs from query-string
15
+ * encoding (`encodeURIComponent`/`URLSearchParams`), where those characters are
16
+ * delimiters and must be escaped. Splat (`*`) values are encoded per segment,
17
+ * preserving `/` separators.
18
+ *
19
+ * See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
20
+ *
21
+ * @example
22
+ * const h = href("/:lang?/about", { lang: "en" })
23
+ * // -> `/en/about`
24
+ *
25
+ * <Link to={href("/products/:id", { id: "abc123" })} />
26
+ *
27
+ * @public
28
+ * @category Utils
29
+ * @mode framework
30
+ * @param path The route path to resolve
31
+ * @param args The route params to use when resolving the path
32
+ * @returns The resolved URL path
17
33
  */
18
34
  declare function href<Path extends keyof Args>(path: Path, ...args: Args[Path]): string;
19
35
  //#endregion
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,16 +8,36 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
+ import { encodePathParam } from "./router/utils.js";
11
12
  //#region lib/href.ts
13
+ function stringify(p) {
14
+ return p == null ? "" : typeof p === "string" ? p : String(p);
15
+ }
12
16
  /**
13
- Returns a resolved URL path for the specified route.
14
-
15
- ```tsx
16
- const h = href("/:lang?/about", { lang: "en" })
17
- // -> `/en/about`
18
-
19
- <Link to={href("/products/:id", { id: "abc123" })} />
20
- ```
17
+ * Returns a resolved URL path for the specified route.
18
+ *
19
+ * Param values are percent-encoded for use in a path segment: characters that
20
+ * would change the URL structure (`/`, `?`, `#`, `%`, whitespace, non-ASCII)
21
+ * are escaped, while characters that RFC 3986 allows literally in a path
22
+ * segment (`$ & + , ; = : @`) are kept as-is. Note this differs from query-string
23
+ * encoding (`encodeURIComponent`/`URLSearchParams`), where those characters are
24
+ * delimiters and must be escaped. Splat (`*`) values are encoded per segment,
25
+ * preserving `/` separators.
26
+ *
27
+ * See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
28
+ *
29
+ * @example
30
+ * const h = href("/:lang?/about", { lang: "en" })
31
+ * // -> `/en/about`
32
+ *
33
+ * <Link to={href("/products/:id", { id: "abc123" })} />
34
+ *
35
+ * @public
36
+ * @category Utils
37
+ * @mode framework
38
+ * @param path The route path to resolve
39
+ * @param args The route params to use when resolving the path
40
+ * @returns The resolved URL path
21
41
  */
22
42
  function href(path, ...args) {
23
43
  let params = args[0];
@@ -25,11 +45,11 @@ function href(path, ...args) {
25
45
  const isRequired = questionMark === void 0;
26
46
  const value = params?.[param];
27
47
  if (isRequired && value === void 0) throw new Error(`Path '${path}' requires param '${param}' but it was not provided`);
28
- return value === void 0 ? "" : "/" + value;
48
+ return value == null ? "" : "/" + encodePathParam(stringify(value));
29
49
  });
30
50
  if (path.endsWith("*")) {
31
51
  const value = params?.["*"];
32
- if (value !== void 0) result += "/" + value;
52
+ if (value !== void 0) result += "/" + stringify(value).split("/").map(encodePathParam).join("/");
33
53
  }
34
54
  return result || "/";
35
55
  }
@@ -236,7 +236,10 @@ declare function invariant<T>(value: T | null | undefined, message?: string): as
236
236
  /**
237
237
  * Creates a string URL path from the given pathname, search, and hash components.
238
238
  *
239
+ * @public
239
240
  * @category Utils
241
+ * @param path The pathname, search, and hash components to combine.
242
+ * @returns The combined URL path.
240
243
  */
241
244
  declare function createPath({
242
245
  pathname,
@@ -246,7 +249,10 @@ declare function createPath({
246
249
  /**
247
250
  * Parses a string URL path into its separate pathname, search, and hash components.
248
251
  *
252
+ * @public
249
253
  * @category Utils
254
+ * @param path The URL path to parse.
255
+ * @returns The parsed pathname, search, and hash components.
250
256
  */
251
257
  declare function parsePath(path: string): Partial<Path>;
252
258
  interface UrlHistory extends History {}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -231,7 +231,10 @@ function createLocation(current, to, state = null, key, mask) {
231
231
  /**
232
232
  * Creates a string URL path from the given pathname, search, and hash components.
233
233
  *
234
+ * @public
234
235
  * @category Utils
236
+ * @param path The pathname, search, and hash components to combine.
237
+ * @returns The combined URL path.
235
238
  */
236
239
  function createPath({ pathname = "/", search = "", hash = "" }) {
237
240
  if (search && search !== "?") pathname += search.charAt(0) === "?" ? search : "?" + search;
@@ -241,7 +244,10 @@ function createPath({ pathname = "/", search = "", hash = "" }) {
241
244
  /**
242
245
  * Parses a string URL path into its separate pathname, search, and hash components.
243
246
  *
247
+ * @public
244
248
  * @category Utils
249
+ * @param path The URL path to parse.
250
+ * @returns The parsed pathname, search, and hash components.
245
251
  */
246
252
  function parsePath(path) {
247
253
  let parsedPath = {};
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -341,7 +341,7 @@ function createRouter(init) {
341
341
  else actionData = null;
342
342
  let loaderData = newState.loaderData ? mergeLoaderData(state.loaderData, newState.loaderData, newState.matches || [], newState.errors) : state.loaderData;
343
343
  let blockers = state.blockers;
344
- if (blockers.size > 0) {
344
+ if (blockers.size > 0 && !isUninterruptedRevalidation) {
345
345
  blockers = new Map(blockers);
346
346
  blockers.forEach((_, k) => blockers.set(k, IDLE_BLOCKER));
347
347
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -686,10 +686,22 @@ interface RouteBranch<RouteObjectType extends RouteObject = RouteObject> {
686
686
  /**
687
687
  * Returns a path with params interpolated.
688
688
  *
689
+ * Param values are percent-encoded for use in a path segment: characters that
690
+ * would change the URL structure (`/`, `?`, `#`, `%`, whitespace, non-ASCII)
691
+ * are escaped, while characters that RFC 3986 allows literally in a path
692
+ * segment (`$ & + , ; = : @`) are kept as-is. Note this differs from query-string
693
+ * encoding (`encodeURIComponent`/`URLSearchParams`), where those characters are
694
+ * delimiters and must be escaped. Splat (`*`) values are encoded per segment,
695
+ * preserving `/` separators.
696
+ *
697
+ * See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
698
+ *
689
699
  * @example
690
700
  * import { generatePath } from "react-router";
691
701
  *
692
702
  * generatePath("/users/:id", { id: "123" }); // "/users/123"
703
+ * generatePath("/files/:name", { name: "a b" }); // "/files/a%20b"
704
+ * generatePath("/releases/:v", { v: "1.0.0+1" }); // "/releases/1.0.0+1"
693
705
  *
694
706
  * @public
695
707
  * @category Utils
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -323,6 +323,8 @@ function rankRouteBranches(branches) {
323
323
  branches.sort((a, b) => a.score !== b.score ? b.score - a.score : compareIndexes(a.routesMeta.map((meta) => meta.childrenIndex), b.routesMeta.map((meta) => meta.childrenIndex)));
324
324
  }
325
325
  const paramRe = /^:[\w-]+$/;
326
+ const partialParamRe = /^:[\w-]+/;
327
+ const partialDynamicSegmentValue = 3.5;
326
328
  const dynamicSegmentValue = 3;
327
329
  const indexRouteValue = 2;
328
330
  const emptySegmentValue = 1;
@@ -334,7 +336,7 @@ function computeScore(path, index) {
334
336
  let initialScore = segments.length;
335
337
  if (segments.some(isSplat)) initialScore += splatPenalty;
336
338
  if (index) initialScore += indexRouteValue;
337
- return segments.filter((s) => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
339
+ return segments.filter((s) => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : partialParamRe.test(segment) ? partialDynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
338
340
  }
339
341
  function compareIndexes(a, b) {
340
342
  return a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]) ? a[a.length - 1] - b[b.length - 1] : 0;
@@ -373,12 +375,66 @@ function matchRouteBranch(branch, pathname, allowPartial = false) {
373
375
  return matches;
374
376
  }
375
377
  /**
378
+ * Characters that `encodeURIComponent` escapes but that are valid literally in
379
+ * a URL path segment. Per RFC 3986 §3.3, a path segment is made of `pchar`:
380
+ *
381
+ * ```
382
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
383
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
384
+ * ```
385
+ *
386
+ * `encodeURIComponent` targets query-string values, where `$ & + , ; = : @`
387
+ * are delimiters and must be escaped — but in a path segment they carry no
388
+ * special meaning, and browsers keep them literal in `location.pathname`.
389
+ * (`! ' ( ) *` and the unreserved set are already left alone by
390
+ * `encodeURIComponent`, so they need no restoring.)
391
+ */
392
+ const PATH_PARAM_OVERESCAPED = {
393
+ "%24": "$",
394
+ "%26": "&",
395
+ "%2B": "+",
396
+ "%2C": ",",
397
+ "%3A": ":",
398
+ "%3B": ";",
399
+ "%3D": "=",
400
+ "%40": "@"
401
+ };
402
+ /**
403
+ * Encodes a param value for interpolation into a single URL path segment.
404
+ *
405
+ * Escapes characters that would break the path (`/ ? # %`, whitespace,
406
+ * non-ASCII, …) while leaving characters that RFC 3986 permits literally in a
407
+ * path segment untouched. Escaping those would needlessly rewrite URLs — e.g.
408
+ * a semver build param `1.0.0+1` would become `1.0.0%2B1` even though browsers
409
+ * display and match the `+` literally in `location.pathname`.
410
+ *
411
+ * See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3))
412
+ *
413
+ * @param value The param value to encode.
414
+ * @returns The encoded value, safe for use as a single path segment.
415
+ */
416
+ function encodePathParam(value) {
417
+ return encodeURIComponent(value).replace(/%(?:24|26|2B|2C|3A|3B|3D|40)/g, (match) => PATH_PARAM_OVERESCAPED[match]);
418
+ }
419
+ /**
376
420
  * Returns a path with params interpolated.
377
421
  *
422
+ * Param values are percent-encoded for use in a path segment: characters that
423
+ * would change the URL structure (`/`, `?`, `#`, `%`, whitespace, non-ASCII)
424
+ * are escaped, while characters that RFC 3986 allows literally in a path
425
+ * segment (`$ & + , ; = : @`) are kept as-is. Note this differs from query-string
426
+ * encoding (`encodeURIComponent`/`URLSearchParams`), where those characters are
427
+ * delimiters and must be escaped. Splat (`*`) values are encoded per segment,
428
+ * preserving `/` separators.
429
+ *
430
+ * See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
431
+ *
378
432
  * @example
379
433
  * import { generatePath } from "react-router";
380
434
  *
381
435
  * generatePath("/users/:id", { id: "123" }); // "/users/123"
436
+ * generatePath("/files/:name", { name: "a b" }); // "/files/a%20b"
437
+ * generatePath("/releases/:v", { v: "1.0.0+1" }); // "/releases/1.0.0+1"
382
438
  *
383
439
  * @public
384
440
  * @category Utils
@@ -401,7 +457,7 @@ function generatePath(originalPath, params = {}) {
401
457
  const [, key, optional, suffix] = keyMatch;
402
458
  let param = params[key];
403
459
  invariant(optional === "?" || param != null, `Missing ":${key}" param`);
404
- return encodeURIComponent(stringify(param)) + suffix;
460
+ return encodePathParam(stringify(param)) + suffix;
405
461
  }
406
462
  return segment.replace(/\?$/g, "");
407
463
  }).filter((segment) => !!segment).join("/");
@@ -465,7 +521,7 @@ function compilePath(path, caseSensitive = false, end = true) {
465
521
  return "(?:/([^\\/]*))?";
466
522
  }
467
523
  return "/([^\\/]+)";
468
- }).replace(/\/([\w-]+)\?(\/|$)/g, "(/$1)?$2");
524
+ }).replace(/\/([\w-]+)\?(?=\/|$|\()/g, "(?:/$1)?");
469
525
  if (path.endsWith("*")) {
470
526
  params.push({ paramName: "*" });
471
527
  regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
@@ -822,4 +878,4 @@ function parseToInfo(_to, basename) {
822
878
  };
823
879
  }
824
880
  //#endregion
825
- export { ErrorResponseImpl, RouterContextProvider, SUPPORTED_ERROR_TYPES, compilePath, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createContext, createDataFunctionUrl, data, decodePath, defaultMapRouteProperties, flattenAndRankRoutes, generatePath, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isBrowser, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, joinPaths, matchPath, matchRoutes, matchRoutesImpl, parseToInfo, prependBasename, redirect, redirectDocument, removeDoubleSlashes, removeTrailingSlash, replace, resolvePath, resolveTo, stripBasename };
881
+ export { ErrorResponseImpl, RouterContextProvider, SUPPORTED_ERROR_TYPES, compilePath, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createContext, createDataFunctionUrl, data, decodePath, defaultMapRouteProperties, encodePathParam, flattenAndRankRoutes, generatePath, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isBrowser, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, joinPaths, matchPath, matchRoutes, matchRoutesImpl, parseToInfo, prependBasename, redirect, redirectDocument, removeDoubleSlashes, removeTrailingSlash, replace, resolvePath, resolveTo, stripBasename };