react-router 7.9.3 → 7.9.4-pre.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.
- package/CHANGELOG.md +106 -9
- package/dist/development/{chunk-65XJMMLO.mjs → chunk-5IRCOFJ2.mjs} +8 -4
- package/dist/development/{chunk-NISHYRIK.mjs → chunk-I2PHXWY4.mjs} +16 -2
- package/dist/{production/chunk-LHDU32KO.js → development/chunk-JPM6TDKY.js} +134 -134
- package/dist/development/{chunk-LZYTN6SO.js → chunk-V7H6ON6M.js} +28 -14
- package/dist/{production/context-BqL5Eckq.d.mts → development/context-DSyS5mLj.d.mts} +1 -1
- package/dist/development/dom-export.d.mts +1 -1
- package/dist/development/dom-export.js +3 -3
- package/dist/development/dom-export.mjs +3 -3
- package/dist/{production/index-react-server-client-2EDmGlsZ.d.mts → development/index-react-server-client-BIz4AUNd.d.mts} +2 -2
- package/dist/development/{index-react-server-client-DKvU8YRr.d.ts → index-react-server-client-BbRcBjrA.d.ts} +1 -1
- package/dist/development/index-react-server-client.d.mts +3 -3
- package/dist/development/index-react-server-client.d.ts +2 -2
- package/dist/development/index-react-server-client.js +4 -4
- package/dist/development/index-react-server-client.mjs +2 -2
- package/dist/development/index-react-server.js +1 -1
- package/dist/development/index-react-server.mjs +1 -1
- package/dist/development/index.d.mts +16 -9
- package/dist/development/index.d.ts +14 -7
- package/dist/development/index.js +105 -99
- package/dist/development/index.mjs +5 -3
- package/dist/development/lib/types/internal.d.mts +3 -3
- package/dist/development/lib/types/internal.d.ts +2 -2
- package/dist/development/lib/types/internal.js +1 -1
- package/dist/development/lib/types/internal.mjs +1 -1
- package/dist/{production/register-DiOIlEq5.d.mts → development/register-C34pU-in.d.ts} +7 -1
- package/dist/development/{register-DiOIlEq5.d.mts → register-CI4bTprK.d.mts} +7 -1
- package/dist/development/{route-data-CDwqkzPE.d.mts → route-data-DZQOUSqV.d.mts} +1 -1
- package/dist/development/{routeModules-BmVo7q9e.d.ts → routeModules-D5iJ6JYT.d.ts} +1 -1
- package/dist/{development/chunk-EUCGRVHH.js → production/chunk-A4C524Z4.js} +134 -134
- package/dist/production/{chunk-GWORLVRM.js → chunk-QIDCISSR.js} +28 -14
- package/dist/production/{chunk-LI6FX3G6.mjs → chunk-TK5RYV7M.mjs} +8 -4
- package/dist/production/{chunk-VAVG4EWR.mjs → chunk-VDTQF36D.mjs} +16 -2
- package/dist/{development/context-BqL5Eckq.d.mts → production/context-DSyS5mLj.d.mts} +1 -1
- package/dist/production/dom-export.d.mts +1 -1
- package/dist/production/dom-export.js +3 -3
- package/dist/production/dom-export.mjs +3 -3
- package/dist/{development/index-react-server-client-2EDmGlsZ.d.mts → production/index-react-server-client-BIz4AUNd.d.mts} +2 -2
- package/dist/production/{index-react-server-client-DKvU8YRr.d.ts → index-react-server-client-BbRcBjrA.d.ts} +1 -1
- package/dist/production/index-react-server-client.d.mts +3 -3
- package/dist/production/index-react-server-client.d.ts +2 -2
- package/dist/production/index-react-server-client.js +4 -4
- package/dist/production/index-react-server-client.mjs +2 -2
- package/dist/production/index-react-server.js +1 -1
- package/dist/production/index-react-server.mjs +1 -1
- package/dist/production/index.d.mts +16 -9
- package/dist/production/index.d.ts +14 -7
- package/dist/production/index.js +105 -99
- package/dist/production/index.mjs +5 -3
- package/dist/production/lib/types/internal.d.mts +3 -3
- package/dist/production/lib/types/internal.d.ts +2 -2
- package/dist/production/lib/types/internal.js +1 -1
- package/dist/production/lib/types/internal.mjs +1 -1
- package/dist/production/{register-DiOIlEq5.d.ts → register-C34pU-in.d.ts} +7 -1
- package/dist/{development/register-DiOIlEq5.d.ts → production/register-CI4bTprK.d.mts} +7 -1
- package/dist/production/{route-data-CDwqkzPE.d.mts → route-data-DZQOUSqV.d.mts} +1 -1
- package/dist/production/{routeModules-BmVo7q9e.d.ts → routeModules-D5iJ6JYT.d.ts} +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,110 @@
|
|
|
1
1
|
# `react-router`
|
|
2
2
|
|
|
3
|
+
## 7.9.4-pre.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- handle external redirects in from server actions ([#14400](https://github.com/remix-run/react-router/pull/14400))
|
|
8
|
+
- New (unstable) `useRoute` hook for accessing data from specific routes ([#14407](https://github.com/remix-run/react-router/pull/14407))
|
|
9
|
+
|
|
10
|
+
For example, let's say you have an `admin` route somewhere in your app and you want any child routes of `admin` to all have access to the `loaderData` and `actionData` from `admin.`
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
// app/routes/admin.tsx
|
|
14
|
+
import { Outlet } from "react-router";
|
|
15
|
+
|
|
16
|
+
export const loader = () => ({ message: "Hello, loader!" });
|
|
17
|
+
|
|
18
|
+
export const action = () => ({ count: 1 });
|
|
19
|
+
|
|
20
|
+
export default function Component() {
|
|
21
|
+
return (
|
|
22
|
+
<div>
|
|
23
|
+
{/* ... */}
|
|
24
|
+
<Outlet />
|
|
25
|
+
{/* ... */}
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
You might even want to create a reusable widget that all of the routes nested under `admin` could use:
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import { unstable_useRoute as useRoute } from "react-router";
|
|
35
|
+
|
|
36
|
+
export function AdminWidget() {
|
|
37
|
+
// How to get `message` and `count` from `admin` route?
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
In framework mode, `useRoute` knows all your app's routes and gives you TS errors when invalid route IDs are passed in:
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
export function AdminWidget() {
|
|
45
|
+
const admin = useRoute("routes/dmin");
|
|
46
|
+
// ^^^^^^^^^^^
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`useRoute` returns `undefined` if the route is not part of the current page:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
export function AdminWidget() {
|
|
54
|
+
const admin = useRoute("routes/admin");
|
|
55
|
+
if (!admin) {
|
|
56
|
+
throw new Error(`AdminWidget used outside of "routes/admin"`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Note: the `root` route is the exception since it is guaranteed to be part of the current page.
|
|
62
|
+
As a result, `useRoute` never returns `undefined` for `root`.
|
|
63
|
+
|
|
64
|
+
`loaderData` and `actionData` are marked as optional since they could be accessed before the `action` is triggered or after the `loader` threw an error:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
export function AdminWidget() {
|
|
68
|
+
const admin = useRoute("routes/admin");
|
|
69
|
+
if (!admin) {
|
|
70
|
+
throw new Error(`AdminWidget used outside of "routes/admin"`);
|
|
71
|
+
}
|
|
72
|
+
const { loaderData, actionData } = admin;
|
|
73
|
+
console.log(loaderData);
|
|
74
|
+
// ^? { message: string } | undefined
|
|
75
|
+
console.log(actionData);
|
|
76
|
+
// ^? { count: number } | undefined
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
If instead of a specific route, you wanted access to the _current_ route's `loaderData` and `actionData`, you can call `useRoute` without arguments:
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
export function AdminWidget() {
|
|
84
|
+
const currentRoute = useRoute();
|
|
85
|
+
currentRoute.loaderData;
|
|
86
|
+
currentRoute.actionData;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This usage is equivalent to calling `useLoaderData` and `useActionData`, but consolidates all route data access into one hook: `useRoute`.
|
|
91
|
+
|
|
92
|
+
Note: when calling `useRoute()` (without a route ID), TS has no way to know which route is the current route.
|
|
93
|
+
As a result, `loaderData` and `actionData` are typed as `unknown`.
|
|
94
|
+
If you want more type-safety, you can either narrow the type yourself with something like `zod` or you can refactor your app to pass down typed props to your `AdminWidget`:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
export function AdminWidget({
|
|
98
|
+
message,
|
|
99
|
+
count,
|
|
100
|
+
}: {
|
|
101
|
+
message: string;
|
|
102
|
+
count: number;
|
|
103
|
+
}) {
|
|
104
|
+
/* ... */
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
3
108
|
## 7.9.3
|
|
4
109
|
|
|
5
110
|
### Patch Changes
|
|
@@ -48,7 +153,6 @@
|
|
|
48
153
|
- Stabilize middleware and context APIs. ([#14215](https://github.com/remix-run/react-router/pull/14215))
|
|
49
154
|
|
|
50
155
|
We have removed the `unstable_` prefix from the following APIs and they are now considered stable and ready for production use:
|
|
51
|
-
|
|
52
156
|
- [`RouterContextProvider`](https://reactrouter.com/api/utils/RouterContextProvider)
|
|
53
157
|
- [`createContext`](https://reactrouter.com/api/utils/createContext)
|
|
54
158
|
- `createBrowserRouter` [`getContext`](https://reactrouter.com/api/data-routers/createBrowserRouter#optsgetcontext) option
|
|
@@ -75,7 +179,7 @@
|
|
|
75
179
|
|
|
76
180
|
- \[UNSTABLE] Add `<RouterProvider unstable_onError>`/`<HydratedRouter unstable_onError>` prop for client side error reporting ([#14162](https://github.com/remix-run/react-router/pull/14162))
|
|
77
181
|
|
|
78
|
-
- server action revalidation opt out via $
|
|
182
|
+
- server action revalidation opt out via $SKIP_REVALIDATION field ([#14154](https://github.com/remix-run/react-router/pull/14154))
|
|
79
183
|
|
|
80
184
|
- Properly escape interpolated param values in `generatePath()` ([#13530](https://github.com/remix-run/react-router/pull/13530))
|
|
81
185
|
|
|
@@ -124,7 +228,6 @@
|
|
|
124
228
|
- Remove dependency on `@types/node` in TypeScript declaration files ([#14059](https://github.com/remix-run/react-router/pull/14059))
|
|
125
229
|
|
|
126
230
|
- Fix types for `UIMatch` to reflect that the `loaderData`/`data` properties may be `undefined` ([#12206](https://github.com/remix-run/react-router/pull/12206))
|
|
127
|
-
|
|
128
231
|
- When an `ErrorBoundary` is being rendered, not all active matches will have loader data available, since it may have been their `loader` that threw to trigger the boundary
|
|
129
232
|
- The `UIMatch.data` type was not correctly handing this and would always reflect the presence of data, leading to the unexpected runtime errors when an `ErrorBoundary` was rendered
|
|
130
233
|
- ⚠️ This may cause some type errors to show up in your code for unguarded `match.data` accesses - you should properly guard for `undefined` values in those scenarios.
|
|
@@ -158,7 +261,6 @@
|
|
|
158
261
|
- \[UNSTABLE] When middleware is enabled, make the `context` parameter read-only (via `Readonly<unstable_RouterContextProvider>`) so that TypeScript will not allow you to write arbitrary fields to it in loaders, actions, or middleware. ([#14097](https://github.com/remix-run/react-router/pull/14097))
|
|
159
262
|
|
|
160
263
|
- \[UNSTABLE] Rename and alter the signature/functionality of the `unstable_respond` API in `staticHandler.query`/`staticHandler.queryRoute` ([#14103](https://github.com/remix-run/react-router/pull/14103))
|
|
161
|
-
|
|
162
264
|
- The API has been renamed to `unstable_generateMiddlewareResponse` for clarity
|
|
163
265
|
- The main functional change is that instead of running the loaders/actions before calling `unstable_respond` and handing you the result, we now pass a `query`/`queryRoute` function as a parameter and you execute the loaders/actions inside your callback, giving you full access to pre-processing and error handling
|
|
164
266
|
- The `query` version of the API now has a signature of `(query: (r: Request) => Promise<StaticHandlerContext | Response>) => Promise<Response>`
|
|
@@ -804,7 +906,6 @@
|
|
|
804
906
|
```
|
|
805
907
|
|
|
806
908
|
Similar to server-side requests, a fresh `context` will be created per navigation (or `fetcher` call). If you have initial data you'd like to populate in the context for every request, you can provide an `unstable_getContext` function at the root of your app:
|
|
807
|
-
|
|
808
909
|
- Library mode - `createBrowserRouter(routes, { unstable_getContext })`
|
|
809
910
|
- Framework mode - `<HydratedRouter unstable_getContext>`
|
|
810
911
|
|
|
@@ -992,7 +1093,6 @@ _No changes_
|
|
|
992
1093
|
- Remove `future.v7_normalizeFormMethod` future flag ([#11697](https://github.com/remix-run/react-router/pull/11697))
|
|
993
1094
|
|
|
994
1095
|
- For Remix consumers migrating to React Router, the `crypto` global from the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) is now required when using cookie and session APIs. This means that the following APIs are provided from `react-router` rather than platform-specific packages: ([#11837](https://github.com/remix-run/react-router/pull/11837))
|
|
995
|
-
|
|
996
1096
|
- `createCookie`
|
|
997
1097
|
- `createCookieSessionStorage`
|
|
998
1098
|
- `createMemorySessionStorage`
|
|
@@ -1001,7 +1101,6 @@ _No changes_
|
|
|
1001
1101
|
For consumers running older versions of Node, the `installGlobals` function from `@remix-run/node` has been updated to define `globalThis.crypto`, using [Node's `require('node:crypto').webcrypto` implementation.](https://nodejs.org/api/webcrypto.html)
|
|
1002
1102
|
|
|
1003
1103
|
Since platform-specific packages no longer need to implement this API, the following low-level APIs have been removed:
|
|
1004
|
-
|
|
1005
1104
|
- `createCookieFactory`
|
|
1006
1105
|
- `createSessionStorageFactory`
|
|
1007
1106
|
- `createCookieSessionStorageFactory`
|
|
@@ -1157,7 +1256,6 @@ _No changes_
|
|
|
1157
1256
|
```
|
|
1158
1257
|
|
|
1159
1258
|
This initial implementation targets type inference for:
|
|
1160
|
-
|
|
1161
1259
|
- `Params` : Path parameters from your routing config in `routes.ts` including file-based routing
|
|
1162
1260
|
- `LoaderData` : Loader data from `loader` and/or `clientLoader` within your route module
|
|
1163
1261
|
- `ActionData` : Action data from `action` and/or `clientAction` within your route module
|
|
@@ -1172,7 +1270,6 @@ _No changes_
|
|
|
1172
1270
|
```
|
|
1173
1271
|
|
|
1174
1272
|
Check out our docs for more:
|
|
1175
|
-
|
|
1176
1273
|
- [_Explanations > Type Safety_](https://reactrouter.com/dev/guides/explanation/type-safety)
|
|
1177
1274
|
- [_How-To > Setting up type safety_](https://reactrouter.com/dev/guides/how-to/setting-up-type-safety)
|
|
1178
1275
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v7.9.
|
|
2
|
+
* react-router v7.9.4-pre.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
withComponentProps,
|
|
61
61
|
withErrorBoundaryProps,
|
|
62
62
|
withHydrateFallbackProps
|
|
63
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-I2PHXWY4.mjs";
|
|
64
64
|
|
|
65
65
|
// lib/dom/ssr/server.tsx
|
|
66
66
|
import * as React from "react";
|
|
@@ -1873,7 +1873,7 @@ function createCallServer({
|
|
|
1873
1873
|
globalVar.__reactRouterDataRouter.__setPendingRerender(
|
|
1874
1874
|
Promise.resolve(payloadPromise).then(async (payload) => {
|
|
1875
1875
|
if (payload.type === "redirect") {
|
|
1876
|
-
if (payload.reload) {
|
|
1876
|
+
if (payload.reload || isExternalLocation(payload.location)) {
|
|
1877
1877
|
window.location.href = payload.location;
|
|
1878
1878
|
return () => {
|
|
1879
1879
|
};
|
|
@@ -1890,7 +1890,7 @@ function createCallServer({
|
|
|
1890
1890
|
const rerender = await payload.rerender;
|
|
1891
1891
|
if (rerender && landedActionId < actionId && globalVar.__routerActionID <= actionId) {
|
|
1892
1892
|
if (rerender.type === "redirect") {
|
|
1893
|
-
if (rerender.reload) {
|
|
1893
|
+
if (rerender.reload || isExternalLocation(rerender.location)) {
|
|
1894
1894
|
window.location.href = rerender.location;
|
|
1895
1895
|
return;
|
|
1896
1896
|
}
|
|
@@ -2460,6 +2460,10 @@ function debounce(callback, wait) {
|
|
|
2460
2460
|
timeoutId = window.setTimeout(() => callback(...args), wait);
|
|
2461
2461
|
};
|
|
2462
2462
|
}
|
|
2463
|
+
function isExternalLocation(location2) {
|
|
2464
|
+
const newLocation = new URL(location2, window.location.href);
|
|
2465
|
+
return newLocation.origin !== window.location.origin;
|
|
2466
|
+
}
|
|
2463
2467
|
|
|
2464
2468
|
// lib/rsc/server.ssr.tsx
|
|
2465
2469
|
import * as React5 from "react";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v7.9.
|
|
2
|
+
* react-router v7.9.4-pre.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -5552,6 +5552,19 @@ function warningOnce(key, cond, message) {
|
|
|
5552
5552
|
warning(false, message);
|
|
5553
5553
|
}
|
|
5554
5554
|
}
|
|
5555
|
+
function useRoute(...args) {
|
|
5556
|
+
const currentRouteId = useCurrentRouteId(
|
|
5557
|
+
"useRoute" /* UseRoute */
|
|
5558
|
+
);
|
|
5559
|
+
const id = args[0] ?? currentRouteId;
|
|
5560
|
+
const state = useDataRouterState("useRouteLoaderData" /* UseRouteLoaderData */);
|
|
5561
|
+
const route = state.matches.find(({ route: route2 }) => route2.id === id);
|
|
5562
|
+
if (route === void 0) return void 0;
|
|
5563
|
+
return {
|
|
5564
|
+
loaderData: state.loaderData[id],
|
|
5565
|
+
actionData: state.actionData?.[id]
|
|
5566
|
+
};
|
|
5567
|
+
}
|
|
5555
5568
|
|
|
5556
5569
|
// lib/components.tsx
|
|
5557
5570
|
import * as React3 from "react";
|
|
@@ -9113,7 +9126,7 @@ var isBrowser = typeof window !== "undefined" && typeof window.document !== "und
|
|
|
9113
9126
|
try {
|
|
9114
9127
|
if (isBrowser) {
|
|
9115
9128
|
window.__reactRouterVersion = // @ts-expect-error
|
|
9116
|
-
"7.9.
|
|
9129
|
+
"7.9.4-pre.0";
|
|
9117
9130
|
}
|
|
9118
9131
|
} catch (e) {
|
|
9119
9132
|
}
|
|
@@ -10271,6 +10284,7 @@ export {
|
|
|
10271
10284
|
useAsyncValue,
|
|
10272
10285
|
useAsyncError,
|
|
10273
10286
|
useBlocker,
|
|
10287
|
+
useRoute,
|
|
10274
10288
|
warnOnce,
|
|
10275
10289
|
mapRouteProperties,
|
|
10276
10290
|
hydrationRouteProperties,
|