Skip to content

Commit 6a5939b

Browse files
committed
Merge branch 'release-next'
2 parents 4475b56 + dcf0c2a commit 6a5939b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+3157
-260
lines changed

CHANGELOG.md

Lines changed: 1083 additions & 0 deletions
Large diffs are not rendered by default.

DEVELOPMENT.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ Changesets will do most of the heavy lifting for our releases. When changes are
2222
- Review the updated `CHANGELOG` files and make any adjustments necessary, then merge the PR into the `release-*` branch.
2323
- `find packages -name 'CHANGELOG.md' -mindepth 2 -maxdepth 2 -exec code {} \;`
2424
- Once the PR is merged, the release workflow will publish the updated packages to npm.
25+
- At this point, you can begin crafting the release notes for the eventual stable release in the root `CHANGELOG.md` file in the repo
26+
- Copy the template for a new release and update the version numbers and links accordingly
27+
- Copy the relevant changelog entries from all packages into the release notes and adjust accordingly
28+
- Commit these changes directly to the `release-*` branch - they will not trigger a new prerelease since they do not include a changeset
2529

2630
### Iterating a pre-release
2731

@@ -34,6 +38,7 @@ You may need to make changes to a pre-release prior to publishing a final stable
3438
- Wait for the release workflow to finish and the Changesets action to open its PR that will increment all versions.
3539
- Review the PR, make any adjustments necessary, and merge it into the `release-*` branch.
3640
- Once the PR is merged, the release workflow will publish the updated packages to npm.
41+
- Make sure you copy over the new changeset contents into stable release notes in the root `CHANGELOG.md` file in the repo
3742

3843
### Publishing the stable release
3944

@@ -42,10 +47,11 @@ You may need to make changes to a pre-release prior to publishing a final stable
4247
- Wait for the release workflow to finish. The Changesets action in the workflow will open a PR that will increment all versions and generate the changelogs for the stable release.
4348
- Review the updated `CHANGELOG` files and make any adjustments necessary.
4449
- `find packages -name 'CHANGELOG.md' -mindepth 2 -maxdepth 2 -exec code {} \;`
45-
- We should remove the changelogs for all pre-releases ahead of publishing the stable version.
50+
- Remove the changelogs for all pre-releases
4651
- [TODO: We should automate this]
47-
- Prepare the GitHub release notes
48-
- Copy the relevant changelog entries from all packages into the Release Notes and adjust accordingly, matching the format used by prior releases
52+
- Finalize the release notes
53+
- This should already be in pretty good shape in the root `CHANGELOG.md` file in the repo
54+
- Do a quick double check that all iterated prerelease changesets got copied over
4955
- Merge the PR into the `release-*` branch.
5056
- Once the PR is merged, the release workflow will publish the updated packages to npm.
5157
- Once the release is published:
@@ -54,7 +60,7 @@ You may need to make changes to a pre-release prior to publishing a final stable
5460
- `git checkout main; git merge --no-ff release-next`
5561
- Merge the `release-*` branch into `dev` **using a non-fast-forward merge** and push it up to GitHub
5662
- `git checkout dev; git merge --no-ff release-next`
57-
- Convert the `[email protected]` tag to a Release on GitHub with the name `v6.x.y`
63+
- Convert the `[email protected]` tag to a Release on GitHub with the name `v6.x.y` and add a deep-link to the release heading in `CHANGELOG.md`
5864

5965
### Hotfix releases
6066

contributors.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
- bbrowning918
3333
- BDomzalski
3434
- bhbs
35+
- bilalk711
3536
- bobziroll
3637
- BrianT1414
3738
- brockross

docs/components/nav-link.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,14 @@ You can pass a render prop as children to customize the content of the `<NavLink
9393

9494
The `end` prop changes the matching logic for the `active` and `pending` states to only match to the "end" of the NavLink's `to` path. If the URL is longer than `to`, it will no longer be considered active.
9595

96-
| Link | URL | isActive |
97-
| ----------------------------- | ------------ | -------- |
98-
| `<NavLink to="/tasks" />` | `/tasks` | true |
99-
| `<NavLink to="/tasks" />` | `/tasks/123` | true |
100-
| `<NavLink to="/tasks" end />` | `/tasks` | true |
101-
| `<NavLink to="/tasks" end />` | `/tasks/123` | false |
96+
| Link | Current URL | isActive |
97+
| ------------------------------ | ------------ | -------- |
98+
| `<NavLink to="/tasks" />` | `/tasks` | true |
99+
| `<NavLink to="/tasks" />` | `/tasks/123` | true |
100+
| `<NavLink to="/tasks" end />` | `/tasks` | true |
101+
| `<NavLink to="/tasks" end />` | `/tasks/123` | false |
102+
| `<NavLink to="/tasks/" end />` | `/tasks` | false |
103+
| `<NavLink to="/tasks/" end />` | `/tasks/` | true |
102104

103105
**A note on links to the root route**
104106

docs/hooks/use-blocker.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
---
2+
title: useBlocker
3+
---
4+
5+
# `useBlocker`
6+
7+
<details>
8+
<summary>Type declaration</summary>
9+
10+
```tsx
11+
declare function useBlocker(
12+
shouldBlock: boolean | BlockerFunction
13+
): Blocker;
14+
15+
type BlockerFunction = (args: {
16+
currentLocation: Location;
17+
nextLocation: Location;
18+
historyAction: HistoryAction;
19+
}) => boolean;
20+
21+
type Blocker =
22+
| {
23+
state: "unblocked";
24+
reset: undefined;
25+
proceed: undefined;
26+
location: undefined;
27+
}
28+
| {
29+
state: "blocked";
30+
reset(): void;
31+
proceed(): void;
32+
location: Location;
33+
}
34+
| {
35+
state: "proceeding";
36+
reset: undefined;
37+
proceed: undefined;
38+
location: Location;
39+
};
40+
41+
interface Location<State = any> extends Path {
42+
state: State;
43+
key: string;
44+
}
45+
46+
interface Path {
47+
pathname: string;
48+
search: string;
49+
hash: string;
50+
}
51+
52+
enum HistoryAction {
53+
Pop = "POP",
54+
Push = "PUSH",
55+
Replace = "REPLACE",
56+
}
57+
```
58+
59+
</details>
60+
61+
The `useBlocker` hook allows you to prevent the user from navigating away from the current location, and present them with a custom UI to allow them to confirm the navigation.
62+
63+
<docs-info>
64+
This only works for client-side navigations within your React Router application and will not block document requests. To prevent document navigations you will need to add your own <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event" target="_blank">`beforeunload`</a> event handler.
65+
</docs-info>
66+
67+
<docs-warning>
68+
Blocking a user from navigating is a bit of an anti-pattern, so please carefully consider any usage of this hook and use it sparingly. In the de-facto use case of preventing a user navigating away from a half-filled form, you might consider persisting unsaved state to `sessionStorage` and automatically re-filling it if they return instead of blocking them from navigating away.
69+
</docs-warning>
70+
71+
```tsx
72+
function ImportantForm() {
73+
let [value, setValue] = React.useState("");
74+
75+
// Block navigating elsewhere when data has been entered into the input
76+
let blocker = useBlocker(
77+
({ currentLocation, nextLocation }) =>
78+
value !== "" &&
79+
currentLocation.pathname !== nextLocation.pathname
80+
);
81+
82+
return (
83+
<Form method="post">
84+
<label>
85+
Enter some important data:
86+
<input
87+
name="data"
88+
value={value}
89+
onChange={(e) => setValue(e.target.value)}
90+
/>
91+
</label>
92+
<button type="submit">Save</button>
93+
94+
{blocker.state === "blocked" ? (
95+
<div>
96+
<p>Are you sure you want to leave?</p>
97+
<button onClick={() => blocker.proceed()}>
98+
Proceed
99+
</button>
100+
<button onClick={() => blocker.reset()}>
101+
Cancel
102+
</button>
103+
</div>
104+
) : null}
105+
</Form>
106+
);
107+
}
108+
```
109+
110+
For a more complete example, please refer to the [example][example] in the repository.
111+
112+
## Properties
113+
114+
### `state`
115+
116+
The current state of the blocker
117+
118+
- `unblocked` - the blocker is idle and has not prevented any navigation
119+
- `blocked` - the blocker has prevented a navigation
120+
- `proceeding` - the blocker is proceeding through from a blocked navigation
121+
122+
### `location`
123+
124+
When in a `blocked` state, this represents the location to which we blocked a navigation. When in a `proceeding` state, this is the location being navigated to after a `blocker.proceed()` call.
125+
126+
## Methods
127+
128+
### `proceed()`
129+
130+
When in a `blocked` state, you may call `blocker.proceed()` to proceed to the blocked location.
131+
132+
### `reset()`
133+
134+
When in a `blocked` state, you may call `blocker.reset()` to return the blocker back to an `unblocked` state and leave the user at the current location.
135+
136+
[example]: https://github.com/remix-run/react-router/tree/main/examples/navigation-blocking

docs/hooks/use-fetcher.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ function SomeComponent() {
107107

108108
## Methods
109109

110-
## `fetcher.load()`
110+
### `fetcher.load(href, options)`
111111

112112
Loads data from a route loader.
113113

@@ -133,7 +133,13 @@ If you find yourself calling this function inside of click handlers, you can pro
133133

134134
<docs-info>Any `fetcher.load` calls that are active on the page will be re-executed as part of revalidation (either after a navigation submission, another fetcher submission, or a `useRevalidator()` call)</docs-info>
135135

136-
## `fetcher.submit()`
136+
#### `options.unstable_flushSync`
137+
138+
The `unstable_flushSync` option tells React Router DOM to wrap the initial state update for this `fetcher.load` in a [`ReactDOM.flushSync`][flush-sync] call instead of the default [`React.startTransition`][start-transition]. This allows you to perform synchronous DOM actions immediately after the update is flushed to the DOM.
139+
140+
<docs-warning>Please note that this API is marked unstable and may be subject to breaking changes without a major release</docs-warning>
141+
142+
### `fetcher.submit()`
137143

138144
The imperative version of `<fetcher.Form>`. If a user interaction should initiate the fetch, you should use `<fetcher.Form>`. But if you, the programmer are initiating the fetch (not in response to a user clicking a button, etc.), then use this function.
139145

@@ -279,3 +285,5 @@ fetcher.formMethod; // "post"
279285
[api-development-strategy]: ../guides/api-development-strategy
280286
[use-submit]: ./use-submit
281287
[use-fetchers]: ./use-fetchers
288+
[flush-sync]: https://react.dev/reference/react-dom/flushSync
289+
[start-transition]: https://react.dev/reference/react/startTransition

docs/hooks/use-navigate.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ interface NavigateOptions {
2020
state?: any;
2121
preventScrollReset?: boolean;
2222
relative?: RelativeRoutingType;
23+
unstable_flushSync?: boolean;
24+
unstable_viewTransition?: boolean;
2325
}
2426

2527
type RelativeRoutingType = "route" | "path";
@@ -89,6 +91,14 @@ function EditContact() {
8991
}
9092
```
9193

94+
## `options.unstable_flushSync`
95+
96+
The `unstable_flushSync` option tells React Router DOM to wrap the initial state update for this navigation in a [`ReactDOM.flushSync`][flush-sync] call instead of the default [`React.startTransition`][start-transition]. This allows you to perform synchronous DOM actions immediately after the update is flushed to the DOM.
97+
98+
<docs-warning>`unstable_flushSync` only works when using a data router, see [Picking a Router][picking-a-router]</docs-warning>
99+
100+
<docs-warning>Please note that this API is marked unstable and may be subject to breaking changes without a major release</docs-warning>
101+
92102
## `options.unstable_viewTransition`
93103

94104
The `unstable_viewTransition` option enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`. If you need to apply specific styles for this view transition, you will also need to leverage the [`unstable_useViewTransitionState()`][use-view-transition-state].
@@ -107,3 +117,5 @@ The `unstable_viewTransition` option enables a [View Transition][view-transition
107117
[use-view-transition-state]: ../hooks//use-view-transition-state
108118
[view-transitions]: https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
109119
[picking-a-router]: ../routers/picking-a-router
120+
[flush-sync]: https://react.dev/reference/react-dom/flushSync
121+
[start-transition]: https://react.dev/reference/react/startTransition

docs/hooks/use-prompt.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
---
2+
title: unstable_usePrompt
3+
---
4+
5+
# `unstable_usePrompt`
6+
7+
<details>
8+
<summary>Type declaration</summary>
9+
10+
```tsx
11+
declare function unstable_usePrompt({
12+
when,
13+
message,
14+
}: {
15+
when: boolean | BlockerFunction;
16+
message: string;
17+
}) {
18+
19+
type BlockerFunction = (args: {
20+
currentLocation: Location;
21+
nextLocation: Location;
22+
historyAction: HistoryAction;
23+
}) => boolean;
24+
25+
interface Location<State = any> extends Path {
26+
state: State;
27+
key: string;
28+
}
29+
30+
interface Path {
31+
pathname: string;
32+
search: string;
33+
hash: string;
34+
}
35+
36+
enum HistoryAction {
37+
Pop = "POP",
38+
Push = "PUSH",
39+
Replace = "REPLACE",
40+
}
41+
```
42+
43+
</details>
44+
45+
The `unstable_usePrompt` hook allows you to prompt the user for confirmation via [`window.confirm`][window-confirm] prior to navigating away from the current location.
46+
47+
<docs-info>
48+
This only works for client-side navigations within your React Router application and will not block document requests. To prevent document navigations you will need to add your own <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event" target="_blank">`beforeunload`</a> event handler.
49+
</docs-info>
50+
51+
<docs-warning>
52+
Blocking a user from navigating is a bit of an anti-pattern, so please carefully consider any usage of this hook and use it sparingly. In the de-facto use case of preventing a user navigating away from a half-filled form, you might consider persisting unsaved state to `sessionStorage` and automatically re-filling it if they return instead of blocking them from navigating away.
53+
</docs-warning>
54+
55+
<docs-warning>
56+
We do not plan to remove the `unstable_` prefix from this hook because the behavior is non-deterministic across browsers when the prompt is open, so React Router cannot guarantee correct behavior in all scenarios. To avoid this non-determinism, we recommend using `useBlocker` instead which also gives you control over the confirmation UX.
57+
</docs-warning>
58+
59+
```tsx
60+
function ImportantForm() {
61+
let [value, setValue] = React.useState("");
62+
63+
// Block navigating elsewhere when data has been entered into the input
64+
unstable_usePrompt({
65+
message: "Are you sure?",
66+
when: ({ currentLocation, nextLocation }) =>
67+
value !== "" &&
68+
currentLocation.pathname !== nextLocation.pathname,
69+
});
70+
71+
return (
72+
<Form method="post">
73+
<label>
74+
Enter some important data:
75+
<input
76+
name="data"
77+
value={value}
78+
onChange={(e) => setValue(e.target.value)}
79+
/>
80+
</label>
81+
<button type="submit">Save</button>
82+
</Form>
83+
);
84+
}
85+
```
86+
87+
[window-confirm]: https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm

docs/hooks/use-submit.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,5 +160,13 @@ Because submissions are navigations, the options may also contain the other navi
160160
- `state`
161161
- `unstable_viewTransition`
162162

163+
### `options.unstable_flushSync`
164+
165+
The `unstable_flushSync` option tells React Router DOM to wrap the initial state update for this submission in a [`ReactDOM.flushSync`][flush-sync] call instead of the default [`React.startTransition`][start-transition]. This allows you to perform synchronous DOM actions immediately after the update is flushed to the DOM.
166+
167+
<docs-warning>Please note that this API is marked unstable and may be subject to breaking changes without a major release</docs-warning>
168+
163169
[pickingarouter]: ../routers/picking-a-router
164170
[form]: ../components/form
171+
[flush-sync]: https://react.dev/reference/react-dom/flushSync
172+
[start-transition]: https://react.dev/reference/react/startTransition

0 commit comments

Comments
 (0)