react-router 8.1.0 → 8.2.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 (143) hide show
  1. package/CHANGELOG.md +16 -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 +3 -2
  5. package/dist/development/index-react-server.js +11 -6
  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.js +1 -1
  11. package/dist/development/lib/dom/lib.js +2 -2
  12. package/dist/development/lib/dom/server.js +1 -1
  13. package/dist/development/lib/dom/ssr/components.js +1 -1
  14. package/dist/development/lib/dom/ssr/data.js +1 -1
  15. package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
  16. package/dist/development/lib/dom/ssr/fallback.js +1 -1
  17. package/dist/development/lib/dom/ssr/fog-of-war.js +1 -1
  18. package/dist/development/lib/dom/ssr/hydration.js +1 -1
  19. package/dist/development/lib/dom/ssr/invariant.js +1 -1
  20. package/dist/development/lib/dom/ssr/links.js +1 -1
  21. package/dist/development/lib/dom/ssr/markup.js +1 -1
  22. package/dist/development/lib/dom/ssr/routeModules.js +1 -1
  23. package/dist/development/lib/dom/ssr/routes-test-stub.js +1 -1
  24. package/dist/development/lib/dom/ssr/routes.js +1 -1
  25. package/dist/development/lib/dom/ssr/server.js +1 -1
  26. package/dist/development/lib/dom/ssr/single-fetch.js +1 -1
  27. package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
  28. package/dist/development/lib/dom-export/hydrated-router.js +1 -1
  29. package/dist/development/lib/errors.js +1 -1
  30. package/dist/development/lib/hooks.d.ts +33 -6
  31. package/dist/development/lib/hooks.js +34 -7
  32. package/dist/development/lib/href.js +6 -3
  33. package/dist/development/lib/router/history.js +1 -1
  34. package/dist/development/lib/router/instrumentation.js +1 -1
  35. package/dist/development/lib/router/router.js +2 -2
  36. package/dist/development/lib/router/url.js +1 -1
  37. package/dist/development/lib/router/utils.js +5 -3
  38. package/dist/development/lib/rsc/browser.js +1 -1
  39. package/dist/development/lib/rsc/errorBoundaries.js +1 -1
  40. package/dist/development/lib/rsc/html-stream/browser.js +1 -1
  41. package/dist/development/lib/rsc/html-stream/server.js +1 -1
  42. package/dist/development/lib/rsc/route-modules.js +1 -1
  43. package/dist/development/lib/rsc/server.rsc.d.ts +3 -2
  44. package/dist/development/lib/rsc/server.ssr.js +1 -1
  45. package/dist/development/lib/server-runtime/cookies.js +1 -1
  46. package/dist/development/lib/server-runtime/crypto.js +1 -1
  47. package/dist/development/lib/server-runtime/data.js +1 -1
  48. package/dist/development/lib/server-runtime/dev.js +1 -1
  49. package/dist/development/lib/server-runtime/entry.js +1 -1
  50. package/dist/development/lib/server-runtime/errors.js +1 -1
  51. package/dist/development/lib/server-runtime/headers.js +1 -1
  52. package/dist/development/lib/server-runtime/invariant.js +1 -1
  53. package/dist/development/lib/server-runtime/mode.js +1 -1
  54. package/dist/development/lib/server-runtime/routeMatching.js +1 -1
  55. package/dist/development/lib/server-runtime/routes.js +1 -1
  56. package/dist/development/lib/server-runtime/server.js +1 -1
  57. package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
  58. package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
  59. package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
  60. package/dist/development/lib/server-runtime/sessions.js +1 -1
  61. package/dist/development/lib/server-runtime/single-fetch.js +1 -1
  62. package/dist/development/lib/server-runtime/urls.js +1 -1
  63. package/dist/development/lib/server-runtime/warnings.js +1 -1
  64. package/dist/development/lib/types/internal.js +1 -1
  65. package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
  66. package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  67. package/dist/development/vendor/turbo-stream-v2/unflatten.js +1 -1
  68. package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
  69. package/dist/production/dom-export.js +1 -1
  70. package/dist/production/index-react-server-client.js +1 -1
  71. package/dist/production/index-react-server.d.ts +3 -2
  72. package/dist/production/index-react-server.js +11 -6
  73. package/dist/production/index.js +1 -1
  74. package/dist/production/lib/actions.js +1 -1
  75. package/dist/production/lib/components.js +1 -1
  76. package/dist/production/lib/context.js +1 -1
  77. package/dist/production/lib/dom/dom.js +1 -1
  78. package/dist/production/lib/dom/lib.js +2 -2
  79. package/dist/production/lib/dom/server.js +1 -1
  80. package/dist/production/lib/dom/ssr/components.js +1 -1
  81. package/dist/production/lib/dom/ssr/data.js +1 -1
  82. package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
  83. package/dist/production/lib/dom/ssr/fallback.js +1 -1
  84. package/dist/production/lib/dom/ssr/fog-of-war.js +1 -1
  85. package/dist/production/lib/dom/ssr/hydration.js +1 -1
  86. package/dist/production/lib/dom/ssr/invariant.js +1 -1
  87. package/dist/production/lib/dom/ssr/links.js +1 -1
  88. package/dist/production/lib/dom/ssr/markup.js +1 -1
  89. package/dist/production/lib/dom/ssr/routeModules.js +1 -1
  90. package/dist/production/lib/dom/ssr/routes-test-stub.js +1 -1
  91. package/dist/production/lib/dom/ssr/routes.js +1 -1
  92. package/dist/production/lib/dom/ssr/server.js +1 -1
  93. package/dist/production/lib/dom/ssr/single-fetch.js +1 -1
  94. package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
  95. package/dist/production/lib/dom-export/hydrated-router.js +1 -1
  96. package/dist/production/lib/errors.js +1 -1
  97. package/dist/production/lib/hooks.d.ts +33 -6
  98. package/dist/production/lib/hooks.js +34 -7
  99. package/dist/production/lib/href.js +6 -3
  100. package/dist/production/lib/router/history.js +1 -1
  101. package/dist/production/lib/router/instrumentation.js +1 -1
  102. package/dist/production/lib/router/router.js +2 -2
  103. package/dist/production/lib/router/url.js +1 -1
  104. package/dist/production/lib/router/utils.js +5 -3
  105. package/dist/production/lib/rsc/browser.js +1 -1
  106. package/dist/production/lib/rsc/errorBoundaries.js +1 -1
  107. package/dist/production/lib/rsc/html-stream/browser.js +1 -1
  108. package/dist/production/lib/rsc/html-stream/server.js +1 -1
  109. package/dist/production/lib/rsc/route-modules.js +1 -1
  110. package/dist/production/lib/rsc/server.rsc.d.ts +3 -2
  111. package/dist/production/lib/rsc/server.ssr.js +1 -1
  112. package/dist/production/lib/server-runtime/cookies.js +1 -1
  113. package/dist/production/lib/server-runtime/crypto.js +1 -1
  114. package/dist/production/lib/server-runtime/data.js +1 -1
  115. package/dist/production/lib/server-runtime/dev.js +1 -1
  116. package/dist/production/lib/server-runtime/entry.js +1 -1
  117. package/dist/production/lib/server-runtime/errors.js +1 -1
  118. package/dist/production/lib/server-runtime/headers.js +1 -1
  119. package/dist/production/lib/server-runtime/invariant.js +1 -1
  120. package/dist/production/lib/server-runtime/mode.js +1 -1
  121. package/dist/production/lib/server-runtime/routeMatching.js +1 -1
  122. package/dist/production/lib/server-runtime/routes.js +1 -1
  123. package/dist/production/lib/server-runtime/server.js +1 -1
  124. package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
  125. package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
  126. package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
  127. package/dist/production/lib/server-runtime/sessions.js +1 -1
  128. package/dist/production/lib/server-runtime/single-fetch.js +1 -1
  129. package/dist/production/lib/server-runtime/urls.js +1 -1
  130. package/dist/production/lib/server-runtime/warnings.js +1 -1
  131. package/dist/production/lib/types/internal.js +1 -1
  132. package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
  133. package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  134. package/dist/production/vendor/turbo-stream-v2/unflatten.js +1 -1
  135. package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
  136. package/docs/explanation/hot-module-replacement.md +1 -1
  137. package/docs/how-to/data-strategy.md +1 -1
  138. package/docs/start/framework/deploying.md +4 -0
  139. package/docs/upgrading/component-routes.md +1 -1
  140. package/docs/upgrading/future.md +33 -0
  141. package/docs/upgrading/router-provider.md +5 -5
  142. package/docs/upgrading/v7.md +39 -22
  143. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # `react-router`
2
2
 
3
+ ## v8.2.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix `href()` to properly stringify and URL-encode param values, matching `generatePath()` ([#15277](https://github.com/remix-run/react-router/pull/15277))
8
+ - splat params preserve path separators while encoding each segment individually
9
+ - Fix dynamic param extraction for routes with optional static segments ([#15200](https://github.com/remix-run/react-router/pull/15200))
10
+ - When a route path contains optional static segments (e.g. `/school?/user/:id`), the internal regex's incorrectly shifted parameter indices resulting in incorrect parameter extraction
11
+ - Consecutive optional static segments (e.g. `/one?/two?`) were only partially handled
12
+ - Preserve navigation blocker state through a revalidation ([#15246](https://github.com/remix-run/react-router/pull/15246))
13
+ - Fix route ranking for dynamic parameters with static extension suffixes ([#15273](https://github.com/remix-run/react-router/pull/15273))
14
+ - These were not being detected as dynamic param segments and instead got incorrectly scored higher as a static segment
15
+ - This meant they could potentially tie truly static routes like `/sitemap.xml` and outrank them based on definition order
16
+ - These are now correctly identified as dynamic parameter segments and scored correctly
17
+ - Use ReactFormState types instead of unknown ([#15263](https://github.com/remix-run/react-router/pull/15263))
18
+
3
19
  ## v8.1.0
4
20
 
5
21
  ### Minor Changes
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.2.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.2.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -2,6 +2,7 @@
2
2
  import * as React from "react";
3
3
  import { CookieParseOptions, CookieParseOptions as CookieParseOptions$1, CookieSerializeOptions, CookieSerializeOptions as CookieSerializeOptions$1 } from "cookie-es";
4
4
  import { BrowserRouter, Form, HashRouter, Link, Links, MemoryRouter, Meta, NavLink, Navigate, Outlet, Route, Router, RouterProvider, Routes, ScrollRestoration, StaticRouter, StaticRouterProvider, unstable_HistoryRouter } from "react-router/internal/react-server-client";
5
+ import { ReactFormState } from "react-dom/client";
5
6
 
6
7
  //#region lib/router/history.d.ts
7
8
  /**
@@ -2324,7 +2325,7 @@ type RSCRenderPayload = {
2324
2325
  matches: RSCRouteMatch[];
2325
2326
  patches?: Promise<RSCRouteManifest[]>;
2326
2327
  nonce?: string;
2327
- formState?: unknown;
2328
+ formState?: ReactFormState;
2328
2329
  };
2329
2330
  type RSCManifestPayload = {
2330
2331
  type: "manifest";
@@ -2350,7 +2351,7 @@ type RSCMatch = {
2350
2351
  payload: RSCPayload;
2351
2352
  };
2352
2353
  type DecodeActionFunction = (formData: FormData) => Promise<() => Promise<unknown>>;
2353
- type DecodeFormStateFunction = (result: unknown, formData: FormData) => unknown;
2354
+ type DecodeFormStateFunction = (result: unknown, formData: FormData) => Promise<ReactFormState | undefined>;
2354
2355
  type DecodeReplyFunction = (reply: FormData | string, options: {
2355
2356
  temporaryReferences: unknown;
2356
2357
  }) => Promise<unknown[]>;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.2.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -389,6 +389,8 @@ function rankRouteBranches(branches) {
389
389
  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)));
390
390
  }
391
391
  const paramRe = /^:[\w-]+$/;
392
+ const partialParamRe = /^:[\w-]+/;
393
+ const partialDynamicSegmentValue = 3.5;
392
394
  const dynamicSegmentValue = 3;
393
395
  const indexRouteValue = 2;
394
396
  const emptySegmentValue = 1;
@@ -400,7 +402,7 @@ function computeScore(path, index) {
400
402
  let initialScore = segments.length;
401
403
  if (segments.some(isSplat)) initialScore += splatPenalty;
402
404
  if (index) initialScore += indexRouteValue;
403
- return segments.filter((s) => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
405
+ return segments.filter((s) => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : partialParamRe.test(segment) ? partialDynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
404
406
  }
405
407
  function compareIndexes(a, b) {
406
408
  return a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]) ? a[a.length - 1] - b[b.length - 1] : 0;
@@ -497,7 +499,7 @@ function compilePath(path, caseSensitive = false, end = true) {
497
499
  return "(?:/([^\\/]*))?";
498
500
  }
499
501
  return "/([^\\/]+)";
500
- }).replace(/\/([\w-]+)\?(\/|$)/g, "(/$1)?$2");
502
+ }).replace(/\/([\w-]+)\?(?=\/|$|\()/g, "(?:/$1)?");
501
503
  if (path.endsWith("*")) {
502
504
  params.push({ paramName: "*" });
503
505
  regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
@@ -2468,7 +2470,7 @@ async function processServerAction(request, basename, decodeReply, loadServerAct
2468
2470
  try {
2469
2471
  let result = await action();
2470
2472
  if (isRedirectResponse(result)) result = prependBasenameToRedirectResponse(result, basename);
2471
- formState = decodeFormState?.(result, formData);
2473
+ formState = await decodeFormState?.(result, formData);
2472
2474
  } catch (error) {
2473
2475
  if (isRedirectResponse(error)) return prependBasenameToRedirectResponse(error, basename);
2474
2476
  if (isResponse(error)) return error;
@@ -2806,6 +2808,9 @@ function canDecodeWithFormData(contentType) {
2806
2808
  }
2807
2809
  //#endregion
2808
2810
  //#region lib/href.ts
2811
+ function stringify(p) {
2812
+ return p == null ? "" : typeof p === "string" ? p : String(p);
2813
+ }
2809
2814
  /**
2810
2815
  Returns a resolved URL path for the specified route.
2811
2816
 
@@ -2822,11 +2827,11 @@ function href(path, ...args) {
2822
2827
  const isRequired = questionMark === void 0;
2823
2828
  const value = params?.[param];
2824
2829
  if (isRequired && value === void 0) throw new Error(`Path '${path}' requires param '${param}' but it was not provided`);
2825
- return value === void 0 ? "" : "/" + value;
2830
+ return value == null ? "" : "/" + encodeURIComponent(stringify(value));
2826
2831
  });
2827
2832
  if (path.endsWith("*")) {
2828
2833
  const value = params?.["*"];
2829
- if (value !== void 0) result += "/" + value;
2834
+ if (value !== void 0) result += "/" + stringify(value).split("/").map(encodeURIComponent).join("/");
2830
2835
  }
2831
2836
  return result || "/";
2832
2837
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.2.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.2.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.2.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.2.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.2.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.2.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -22,7 +22,7 @@ import * as React$1 from "react";
22
22
  //#region lib/dom/lib.tsx
23
23
  const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
24
24
  try {
25
- if (isBrowser) window.__reactRouterVersion = "8.1.0";
25
+ if (isBrowser) window.__reactRouterVersion = "8.2.0";
26
26
  } catch (e) {}
27
27
  /**
28
28
  * Create a new {@link DataRouter| data router} that manages the application
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.2.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -9,6 +9,9 @@
9
9
  * @license MIT
10
10
  */
11
11
  //#region lib/href.ts
12
+ function stringify(p) {
13
+ return p == null ? "" : typeof p === "string" ? p : String(p);
14
+ }
12
15
  /**
13
16
  Returns a resolved URL path for the specified route.
14
17
 
@@ -25,11 +28,11 @@ function href(path, ...args) {
25
28
  const isRequired = questionMark === void 0;
26
29
  const value = params?.[param];
27
30
  if (isRequired && value === void 0) throw new Error(`Path '${path}' requires param '${param}' but it was not provided`);
28
- return value === void 0 ? "" : "/" + value;
31
+ return value == null ? "" : "/" + encodeURIComponent(stringify(value));
29
32
  });
30
33
  if (path.endsWith("*")) {
31
34
  const value = params?.["*"];
32
- if (value !== void 0) result += "/" + value;
35
+ if (value !== void 0) result += "/" + stringify(value).split("/").map(encodeURIComponent).join("/");
33
36
  }
34
37
  return result || "/";
35
38
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.2.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.2.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.2.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.2.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.2.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;
@@ -465,7 +467,7 @@ function compilePath(path, caseSensitive = false, end = true) {
465
467
  return "(?:/([^\\/]*))?";
466
468
  }
467
469
  return "/([^\\/]+)";
468
- }).replace(/\/([\w-]+)\?(\/|$)/g, "(/$1)?$2");
470
+ }).replace(/\/([\w-]+)\?(?=\/|$|\()/g, "(?:/$1)?");
469
471
  if (path.endsWith("*")) {
470
472
  params.push({ paramName: "*" });
471
473
  regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.2.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.2.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.2.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.2.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.2.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -3,6 +3,7 @@ import { Location } from "../router/history.js";
3
3
  import { ActionFunction, LoaderFunction, Params, RouterContextProvider, ShouldRevalidateFunction } from "../router/utils.js";
4
4
  import { ClientActionFunction, ClientLoaderFunction, HeadersFunction, LinksFunction, MetaFunction } from "../dom/ssr/routeModules.js";
5
5
  import * as React$1 from "react";
6
+ import { ReactFormState } from "react-dom/client";
6
7
 
7
8
  //#region lib/rsc/server.rsc.d.ts
8
9
  declare function getRequest(): Request;
@@ -71,7 +72,7 @@ type RSCRenderPayload = {
71
72
  matches: RSCRouteMatch[];
72
73
  patches?: Promise<RSCRouteManifest[]>;
73
74
  nonce?: string;
74
- formState?: unknown;
75
+ formState?: ReactFormState;
75
76
  };
76
77
  type RSCManifestPayload = {
77
78
  type: "manifest";
@@ -97,7 +98,7 @@ type RSCMatch = {
97
98
  payload: RSCPayload;
98
99
  };
99
100
  type DecodeActionFunction = (formData: FormData) => Promise<() => Promise<unknown>>;
100
- type DecodeFormStateFunction = (result: unknown, formData: FormData) => unknown;
101
+ type DecodeFormStateFunction = (result: unknown, formData: FormData) => Promise<ReactFormState | undefined>;
101
102
  type DecodeReplyFunction = (reply: FormData | string, options: {
102
103
  temporaryReferences: unknown;
103
104
  }) => Promise<unknown[]>;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.1.0
2
+ * react-router v8.2.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.2.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.2.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *