Commit Graph

1230 Commits

Author SHA1 Message Date
sebmarkbage dd554f3547 Check if a child is a new child before calling moveBefore (#32567)
This fixes a critical issue with moveBefore. I was told that the
disconnected -> connected case was going to be relaxed and not be an
error but apparently that is not the case.

This means that we can't use this for initial insertions. Only moves.

Unfortunately React's internals doesn't distinguish these cases. This
adds a hack that checks each nodes but this is pretty bad for
performance. We should only call this in one or the other case.

Given that we still need feature detection. Both of which means that
these calls are no longer inlined and this extra code. I wonder if it's
even worth it given that you can't even rely on it working anyway since
not all browsers have it. Kind of don't want to ship this until all
browsers have it.

Even then we'd ideally refactor React to use separate code paths for
initial insertion vs moves. Which leads to some unfortunate code
duplication.

DiffTrain build for [99e1024051](https://github.com/facebook/react/commit/99e1024051f2e6b2d2849b966e2f4354aef2a1d0)
2025-03-10 15:18:48 -07:00
jackpope 64aba73cf4 Make renameElementSymbol dynamic for native fb (#32566)
Use variant to begin rolling this out internally.

DiffTrain build for [50ab2dde94](https://github.com/facebook/react/commit/50ab2dde940bf0027773a944da005277b3d5598a)
2025-03-10 12:30:09 -07:00
sammy-SC ffe288a749 Fix asserts caused by OffscreenComponent rendering in React Native with passChildrenWhenCloningPersistedNodes (#32528)
<!--
  Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.

Before submitting a pull request, please make sure the following is
done:

1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
  2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
  9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
  10. If you haven't already, complete the CLA.

Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->

## Summary

<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->

This PR fixes asserts when `passChildrenWhenCloningPersistedNodes` is
enabled for React Native and OffscreenComponent child rendering unhides
host components.

Discussions around possible fixes for the asserts seen in React Native
suggested changing the way we handle hiding/unhiding host components by
updating the fiber state with the hidden host component instead of
submitting a hidden clone Fabric and keeping the original as the current
fiber.

Implementing this fix would require holding onto the original styling of
the hidden host component. The reconciler updates the styling by adding
`display: none` to hide the contents. If the original host component was
already hidden, the renderer would lose that information and remove the
styling when showing the contents again.

To reduce the changes required to make
`passChildrenWhenCloningPersistedNodes` work, this PR falls back to the
original cloning method when OffscreenComponents are part of the
children needed to be added back. This effectively resolve the asserts
triggered by the feature in RN and improves overall performance.

## How did you test this change?

<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
  If you leave this empty, your PR will very likely be closed.
-->

This fix was tested by enabling `passChildrenWhenCloningPersistedNodes`
in an app built with React Native that had a repro for triggering the
asserts. The asserts do not occur anymore when using the changes in this
PR.

---------

Co-authored-by: Nick <lefever@meta.com>

DiffTrain build for [cc680065c3](https://github.com/facebook/react/commit/cc680065c33739cc4c8cd2e8a67312b0c16a6ccc)
2025-03-07 09:09:51 -08:00
eps1lon 5fa669315f Add Owner Stack to attribute hydration mismatches (#32538)
DiffTrain build for [029e8bd618](https://github.com/facebook/react/commit/029e8bd618af23fbdd9efdac565ad81f7d4640d8)
2025-03-06 08:18:17 -08:00
eps1lon 4f50377ac2 Support beforetoggle/toggle events for dialog (#32479)
DiffTrain build for [aac177c484](https://github.com/facebook/react/commit/aac177c48439ab294f72e8b5a85059daa3f8a5ee)
2025-03-05 10:51:01 -08:00
sebmarkbage 7020910640 During a Swipe Gesture Render a Clone Offscreen and Animate it Onscreen (#32500)
This is really the essence mechanism of the `useSwipeTransition`
feature.

We don't want to immediately switch to the destination state when
starting a gesture. The effects remain mounted on the current state. We
want the current state to be "live". This is important to for example
allow a video to keeping playing while starting a swipe (think
TikTok/Reels) and not stop until you've committed the action. The only
thing that can be live is the "new" state. Therefore we treat the
destination as the "old" state and perform a reverse animation from
there.

Ideally we could apply the old state to the DOM tree, take a snapshot
and then revert it back in the mutation of `startViewTransition`.
Unfortunately, the way `startViewTransition` was designed it always
paints one frame of the "old" state which would lead this to cause a
flicker.

To work around this, we need to create a clone of any View Transition
boundary that might be mutated and then render that offscreen. That way
we can render the "current" state on screen and the "destination" state
offscreen for the screenshots. Being mutated can be either due to React
doing a DOM mutation or if a child boundary resizes that causes the
parent to relayout. We don't have to do this for insertions or deletions
since they only appear on one side.

The worst case scenario is that we have to clone the whole root. That's
what this first PR implements. We clone the container and if it's not
absolutely positioned, we position it on top of the current one. If the
container is `document` or `<html>` we instead clone the `<body>` tag
since it's the only one we can insert a duplicate of. If the container
is deep in the tree we clone just that even though technically we should
probably clone the whole document in that case. We just keep the impact
smaller. Ideally though we'd never hit this case. In fact, if we clone
the document we issue a warning (always for now) since you probably
should optimize this. In the future I intend to add optimizations when
affected View Transition boundaries are absolutely positioned since they
cannot possibly relayout the parent. This would be the ideal way to use
this feature most efficiently but it still works without it.

Since we render the "old" state outside the viewport, we need to then
adjust the animation to put it back into the viewport. This is the
trickiest part to get right while still preserving any customization of
the View Transitions done using CSS. This current approach reapplies all
the animations with adjusted keyframes.

In the case of an "exit" the pseudo-element itself is positioned outside
the viewport but since we can't programmatically update the style of the
pseudo-element itself we instead adjust all the keyframes to put it back
into the viewport. If there is no animation on the group we add one.

In the case of an "update" the pseudo-element is positioned on the new
state which is already inside the viewport. However, the auto-generated
animation of the group has a starting keyframe that starts outside the
viewport. In this case we need to adjust that keyframe.

In the future I might explore a technique that inserts stylesheets
instead of mutating the animations. It might be simpler. But whatever
hacks work to maximize the compatibility is best.

DiffTrain build for [e9252bcdcc](https://github.com/facebook/react/commit/e9252bcdccf7f8f691081e4d48ca47657bc723f9)
2025-03-04 17:15:30 -08:00
rickhanlonii c2530474d3 [flags] remove enableOwnerStacks (#32426)
Bassed off: https://github.com/facebook/react/pull/32425

Wait to land internally.

[Commit to
review.](https://github.com/facebook/react/pull/32426/commits/66aa6a4dbb78106b4f3d3eb367f5c27eb8f30c66)

This has landed everywhere

DiffTrain build for [e0fe347967](https://github.com/facebook/react/commit/e0fe3479671555e01531dbc3d2fd85d5bd4c5a56)
2025-03-04 09:40:20 -08:00
sebmarkbage 0fc4c58f7c Polyfill onScrollEnd Event in Safari (#32427)
We added support for `onScrollEnd` in #26789 but it only works in Chrome
and Firefox. Safari still doesn't support `scrollend` and there's no
indication that they will anytime soon so this polyfills it.

While I don't particularly love our synthetic event system this tries to
stay within the realm of how our other polyfills work. This implements
all `onScrollEnd` events as a plugin.

The basic principle is to first feature detect the `onscrollend` DOM
property to see if there's native support and otherwise just use the
native event.

Then we listen to `scroll` events and set a timeout. If we don't get any
more scroll events before the timeout we fire `onScrollEnd`. Basically
debouncing it. If we're currently pressing down on touch or a mouse then
we wait until it is lifted such as if you're scrolling with a finger or
using the scrollbars on desktop but isn't currently moving.

If we do get any native events even though we're in polyfilling mode, we
use that as an indication to fire the `onScrollEnd` early.

Part of the motivation is that this becomes extra useful pair for
https://github.com/facebook/react/pull/32422. We also probably need
these events to coincide with other gesture related internals so you're
better off using our polyfill so they're synced.

DiffTrain build for [605a880c8c](https://github.com/facebook/react/commit/605a880c8c5191e9f8c52468458709cd17a486c1)
2025-03-03 11:30:13 -08:00
sebmarkbage 0f71e700f0 Add Commit Scaffolding for Gestures (#32451)
This adds a `ReactFiberApplyGesture` which is basically intended to be a
fork of the phases in `ReactFiberCommitWork` except for the fake commit
that `useSwipeTransition` does. So far none of the phases are actually
implemented yet. This is just the scaffolding around them so I can fill
them in later.

The important bit is that we call `startViewTransition` (via the
`startGestureTransition` Config) when a gesture starts. We add a paused
animation to prevent the transition from committing (even if the
ScrollTimeline goes to 100%). This also locks the documents so that we
can't commit any other Transitions until it completes.

When the gesture completes (scroll end) then we stop the gesture View
Transition. If there's no new work scheduled we do that immediately but
if there was any new work already scheduled, then we assume that this
will potentially commit the new state. So we wait for that to finish.
This lets us lock the animation in its state instead of snapping back
and then applying the real update.

Using this technique we can't actually run a View Transition from the
current state to the actual committed state because it would snap back
to the beginning and then run the View Transition from there. Therefore
any new commit needs to skip View Transitions even if it should've
technically animated to that state. We assume that the new state is the
same as the optimistic state you already swiped to. An alternative to
this technique could be to commit the optimistic state when we cancel
and then apply any new updates o top of that. I might explore that in
the future.

Regardless it's important that the `action` associated with the swipe
schedules some work before we cancel. Otherwise it risks reverting
first. So I had to update this in the fixture.

DiffTrain build for [3607f4838a](https://github.com/facebook/react/commit/3607f4838a8f4a87160da36aa26bb1432d7a5f11)
2025-02-27 13:50:46 -08:00
poteto 57b7e4c5ea [forgive] Add basic codelens provider (#32476)
Adds a first codelens provider for successfully compiled functions. A
later PR will add an actual command that will fire when the codelens is
clicked

![Screenshot 2025-02-25 at 6 40
20 PM](https://github.com/user-attachments/assets/924586e0-f70a-45d1-b0e6-a89af9371c8d)

DiffTrain build for [92e65ca68f](https://github.com/facebook/react/commit/92e65ca68f6bfc6be515ccacaa918e33b63911df)
2025-02-25 16:01:16 -08:00
sebmarkbage bcae4ac199 Use valid CSS selectors in useId format (#32001)
For the `useId` algorithm we used colon `:` before and after.
https://github.com/facebook/react/pull/23360

This avoids collisions in general by using an unusual characters. It
also avoids collisions when concatenated with some other ID.
Unfortunately, `:` is not a valid character in `view-transition-name`.

This PR swaps the format from:

```
:r123:
```

To the unicode:

```
«r123»
```

Which is valid CSS selectors. This also allows them being used for
`querySelector()` which we didn't really find a legit use for but seems
ok-ish.

That way you can get a view-transition-name that you can manually
reference. E.g. to generate styles:

```js
const id = useId();
return <>
  <style>{`
    ::view-transition-group(${id}) { ... }
    ::view-transition-old(${id}) { ... }
    ::view-transition-new(${id}) { ... }
  `}</style>
  <ViewTransition name={id}>...</ViewTransition>
</>;
```

DiffTrain build for [2e4db3344f](https://github.com/facebook/react/commit/2e4db3344f030fe622152ecc231a7c99a81a9c9d)
2025-02-25 09:53:58 -08:00
eps1lon 53597597be Include component name in "async/await is not supported" error message if available (#32435)
DiffTrain build for [22e39ea72e](https://github.com/facebook/react/commit/22e39ea72e9d10f6634ea580aaba49c2e759ef0e)
2025-02-25 01:54:27 -08:00
rickhanlonii 920b646138 [flags] remove enableRemoveConsolePatches (#32425)
wait to merge until we sync
https://github.com/facebook/react/pull/32376, since that enables it in
some testing builds that might break

DiffTrain build for [2567726503](https://github.com/facebook/react/commit/25677265038b89c1ee3000e0669339ed160d9d75)
2025-02-24 07:08:48 -08:00
rubennorte 66108fa807 [RN] Move definition of public instances to ReactNativePrivateInterface (#32446)
## Summary

> [!NOTE]
> This only modifies types, so shouldn't have an impact at runtime.

Some time ago we moved some type definitions from React to React Native
in #26437.

This continues making progress on that so values that are created by
React Native and passed to the React renderer (in this case public
instances) are actually defined in React Native and not in React.

This will allow us to modify the definition of some of these types
without having to make changes in the React repository (in the short
term, we want to refactor PublicInstance from an object to an interface,
and then modify that interface to add all the new DOM methods).

## How did you test this change?

Manually synced `ReactNativeTypes` on top of
https://github.com/facebook/react-native/pull/49602 and verified Flow
passes.

DiffTrain build for [9dd378ff12](https://github.com/facebook/react/commit/9dd378ff1222335ff133bab2d61001fcc84a1c56)
2025-02-24 05:51:57 -08:00
SamChou19815 0cf3a7f681 [flow] Eliminate usage of global React types in ReactNativeTypes.js (#32330)
DiffTrain build for [70f1d766e8](https://github.com/facebook/react/commit/70f1d766e8ae7ca3701193abb8c8a9f2fdbdaa9d)
2025-02-20 09:48:32 -08:00
jackpope 0719d18c94 Revert "Ship enableFabricCompleteRootInCommitPhase (#32318)" (#32434)
This reverts commit 8759c5c8d6 /
https://github.com/facebook/react/pull/32318

We discovered that the experiment setup for this was faulty and we need
to re-run as a back test.

DiffTrain build for [885532c124](https://github.com/facebook/react/commit/885532c124f32436723cd51627d06de6e8c13fdd)
2025-02-20 09:36:52 -08:00
rickhanlonii 34e060ab90 [flags] enable owner stacks everywhere (#32376)
this is now canary and on everywhere

DiffTrain build for [8a7b487e3b](https://github.com/facebook/react/commit/8a7b487e3b171c91f2fe18e9142af53f4dd83454)
2025-02-18 07:35:32 -08:00
hoxyq 40fb50ae6c Change TouchedViewDataAtPoint type in ReactNativeTypes to use supported by Flow tooling syntax (#32382)
## Summary

The `flow-api-translator` from the `hermes` repo does not support flow
type spreads. It is currently not able to digest the ReactNativeTypes
file as it contains unsupported syntax. The simplest solution is to
change the type of the `TouchedViewDataAtPoint` to equivalent, yet
supported by the Flow tooling. In this case the intersection can be used
as
the `TouchedViewDataAtPoint` and `InspectorData` have no common
property.

## How did you test this change?

Run yarn flow native

DiffTrain build for [e670e72fa0](https://github.com/facebook/react/commit/e670e72fa076449e40172e20d17cc67c1c15419c)
2025-02-14 06:16:16 -08:00
sebmarkbage d3a5cf7e1d Add useSwipeTransition Hook Behind Experimental Flag (#32373)
This Hook will be used to drive a View Transition based on a gesture.

```js
const [value, startGesture] = useSwipeTransition(prev, current, next);
```

The `enableSwipeTransition` flag will depend on `enableViewTransition`
flag but we may decide to ship them independently. This PR doesn't do
anything interesting yet. There will be a lot more PRs to build out the
actual functionality. This is just wiring up the plumbing for the new
Hook.

This first PR is mainly concerned with how the whole starts (and stops).
The core API is the `startGesture` function (although there will be
other conveniences added in the future). You can call this to start a
gesture with a source provider. You can call this multiple times in one
event to batch multiple Hooks listening to the same provider. However,
each render can only handle one source provider at a time and so it does
one render per scheduled gesture provider.

This uses a separate `GestureLane` to drive gesture renders by marking
the Hook as having an update on that lane. Then schedule a render. These
renders should be blocking and in the same microtask as the
`startGesture` to ensure it can block the paint. So it's similar to
sync.

It may not be possible to finish it synchronously e.g. if something
suspends. If so, it just tries again later when it can like any other
render. This can also happen because it also may not be possible to
drive more than one gesture at a time like if we're limited to one View
Transition per document. So right now you can only run one gesture at a
time in practice.

These renders never commit. This means that we can't clear the
`GestureLane` the normal way. Instead, we have to clear only the root's
`pendingLanes` if we don't have any new renders scheduled. Then wait
until something else updates the Fiber after all gestures on it have
stopped before it really clears.

DiffTrain build for [a53da6abe1](https://github.com/facebook/react/commit/a53da6abe1593483098df2baf927fe07d80153a5)
2025-02-13 13:12:18 -08:00
eps1lon dd64c5d03c Ensure captureOwnerStack returns null when no stack is available (#32353)
Co-authored-by: Younes Henni <youneshenniwrites@gmail.com>

DiffTrain build for [c6a7e18636](https://github.com/facebook/react/commit/c6a7e18636e610efd3aa7a437bbcaf321bf73abd)
2025-02-13 09:16:28 -08:00
rubennorte 469ec7cde5 [RN] Set up test to create public instances lazily in Fabric (#32363)
## Summary

In React Native, public instances and internal host nodes are not
represented by the same object (ReactNativeElement & shadow nodes vs.
just DOM elements), and the only one that's required for rendering is
the shadow node. Public instances are generally only necessary when
accessed via refs or events, and that usually happens for a small amount
of components in the tree.

This implements an optimization to create the public instance on demand,
instead of eagerly creating it when creating the host node. We expect
this to improve performance by reducing the logic we do per node and the
number of object allocations.

## How did you test this change?

Manually synced the changes to React Native and run Fantom tests and
benchmarks, with the flag enabled and disabled. All tests pass in both
cases, and benchmarks show a slight but consistent performance
improvement.

DiffTrain build for [f83903bfcc](https://github.com/facebook/react/commit/f83903bfcc5a61811bd1b69b14f0ebbac4754462)
2025-02-12 05:58:28 -08:00
poteto f88c2a0c76 Added dev-only warning for null/undefined create in use*Effect (#32355)
## Summary

Fixes #32354.

Re-creation of #15197: adds a dev-only warning if `create == null` to
the three `use*Effect` functions:

* `useEffect`
* `useInsertionEffect`
* `useLayoutEffect`

Updates the warning to match the same text given in the
`react/exhaustive-deps` lint rule.

## How did you test this change?

I applied the changes manually within `node_modules/` on a local clone
of
https://github.com/JoshuaKGoldberg/repros/tree/react-use-effect-no-arguments.

Please pardon me for opening a PR addressing a not-accepted issue. I was
excited to get back to #15194 -> #15197 now that I have time. 🙂

---------

Co-authored-by: lauren <poteto@users.noreply.github.com>

DiffTrain build for [192555bb0e](https://github.com/facebook/react/commit/192555bb0ed88db30f91c58651c421f178f90384)
2025-02-11 14:06:55 -08:00
poteto b4cbede0e9 [crud] Remove useResourceEffect (#32206)
Removes useResourceEffect.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32206).
* __->__ #32206
* #32205

DiffTrain build for [a69b80d07e](https://github.com/facebook/react/commit/a69b80d07e5d1bf363ed15d6209a55b35e0765c2)
2025-02-11 11:25:52 -08:00
poteto 92fac77aa4 [crud] Rename useResourceEffect flag (#32204)
Rename the flag in preparation for the overload.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32204).
* #32206
* #32205
* __->__ #32204

DiffTrain build for [0461c0d8a4](https://github.com/facebook/react/commit/0461c0d8a49730d1c8ebca2071d9bb7adfc8ac92)
2025-02-11 11:14:38 -08:00
poteto 8d80d81894 [crud] Narrow resource type (#32203)
Small refactor to the `resource` type to narrow it to an arbitrary
object or void/null instead of the top type. This makes the overload on
useEffect simpler since the return type of create is no longer widened
to the top type when we merge their definitions.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32203).
* #32206
* #32205
* #32204
* __->__ #32203

DiffTrain build for [899e3d1297](https://github.com/facebook/react/commit/899e3d1297ec15a5aa8d73e2f1bd478918090a12)
2025-02-11 11:03:41 -08:00
lauren ea2c5b208a [builds/facebook-fbsource] Add workflow to close direct PRs (#32357) 2025-02-11 13:09:38 -05:00
poteto 7e59b47d91 [react-native] Suppress Flow nonstrict-import check in ReactNativeTypes (#32349)
Summary: Unblock internal sync.

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:

DiffTrain build for [cd90a4d8c0](https://github.com/facebook/react/commit/cd90a4d8c0d5dbaa8ab61e839b112b1518d5058f)
2025-02-10 12:52:24 -08:00
poteto 2cf442e812 [react-native] fix divergence in synced code (#32348)
Alternative to #32334

DiffTrain build for [3dd2c62770](https://github.com/facebook/react/commit/3dd2c627707fea4f45fd8e5cc583036a72e3f77b)
2025-02-10 11:18:13 -08:00
jackpope e74ebbaf94 Ship enableFabricCompleteRootInCommitPhase (#32318)
DiffTrain build for [8759c5c8d6](https://github.com/facebook/react/commit/8759c5c8d6aef34df576827215ff7ebaeafc79ea)
2025-02-07 08:18:36 -08:00
gnoff 0b22ef9dc6 [Fiber][Dev] Relax dom nesting validation when the root is a Document, html tag, or body tag (#32252)
followup to
* https://github.com/facebook/react/pull/32069
* https://github.com/facebook/react/pull/32163
* https://github.com/facebook/react/pull/32224

in react-dom in Dev we validate that the tag nesting is valid. This is
motivated primarily because while browsers are tolerant to poor HTML
there are many cases that if server rendered will be hydrated in a way
that will break hydration.

With the changes to singleton scoping where the document body is now the
implicit render/hydration context for arbitrary tags at the root we need
to adjust the validation logic to allow for valid programs such as
rendering divs as a child of a Document (since this div will actually
insert into the body).

DiffTrain build for [a0fdb63060](https://github.com/facebook/react/commit/a0fdb6306043b9f049106e58dcec107d8dbed2b1)
2025-02-06 15:11:28 -08:00
gnoff 2ca4fae6b8 [Fiber] getHoistableRoot() should account for Document containers (#32321)
While modern DOM implementations all support getRootNode if you are
running React in a runtime which does not the fallback logic which uses
`.ownerDocument` works everywhere except when the container is a
Document itself. This change corrects this by returning the container
intsance if it is a Document type.

DiffTrain build for [b48e739998](https://github.com/facebook/react/commit/b48e739998432fc9672a42d0d04515980b8cae82)
2025-02-06 14:36:11 -08:00
rickhanlonii 9f6cb64e97 Export addTransitionType for www (#32311)
need dis based api

DiffTrain build for [ff6283340a](https://github.com/facebook/react/commit/ff6283340a10bb72ad0fb16ca027606a9ea1e67c)
2025-02-05 15:37:56 -08:00
jackpope 96aa3adcd4 Set enableViewTransition to dynamic for www (#32306)
Unblocks internal experimentation

DiffTrain build for [32b411496b](https://github.com/facebook/react/commit/32b411496b92455cede3b286eb37c8b183989051)
2025-02-04 12:58:38 -08:00
gnoff 781b67895f [Fiber] Disable comments as containers in OSS (#32250)
3 years ago we partially disabled comment nodes as valid containers.
Some unflagged support was left in due to legacy APIs like
`unmountComponentAtNode` and `unstable_renderSubtreeIntoContainer` but
these were since removed in React 19. This update flags the remaining
uses of comments as containers.

DiffTrain build for [0605cd9f38](https://github.com/facebook/react/commit/0605cd9f38f8b9d0ca6f8bd9dd3409db8d6c5c81)
2025-02-04 12:45:18 -08:00
gnoff 3f18106258 [Fiber] support hydration when rendering Suspense anywhere (#32224)
follow up to https://github.com/facebook/react/pull/32163

This continues the work of making Suspense workable anywhere in a
react-dom tree. See the prior PRs for how we handle server rendering and
client rendering. In this change we update the hydration implementation
to be able to locate expected nodes. In particular this means hydration
understands now that the default hydration context is the document body
when the container is above the body.

One case that is unique to hydration is clearing Suspense boundaries.
When hydration fails or when the server instructs the client to recover
an errored boundary it's possible that the html, head, and body tags in
the initial document were written from a fallback or a different primary
content on the server and need to be replaced by the client render.
However these tags (and in the case of head, their content) won't be
inside the comment nodes that identify the bounds of the Suspense
boundary. And when client rendering you may not even render the same
singletons that were server rendered. So when server rendering a
boudnary which contributes to the preamble (the html, head, and body tag
openings plus the head contents) we emit a special marker comment just
before closing the boundary out. This marker encodes which parts of the
preamble this boundary owned. If we need to clear the suspense boundary
on the client we read this marker and use it to reset the appropriate
singleton state.

DiffTrain build for [8bda71558c](https://github.com/facebook/react/commit/8bda71558c8b6f9f19af33271f1bfd0251a1c071)
2025-02-04 12:36:28 -08:00
gnoff 0c2639f426 Reconciler: Combine identical cases in findParent (#32210)
## Summary

When lookup `Parent`, `HostRoot` and `HostPortal` should be merged,
because when creating a `Portal`, it will also include
`containerInfo`(So we can directly use this `containerInfo` to delete
the real DOM nodes.), so there is no need to handle them separately.

## How did you test this change?

No behavior changes, all existing tests pass.

DiffTrain build for [19ca800caa](https://github.com/facebook/react/commit/19ca800caa01eec2f5e65e547c67b11592bec8b0)
2025-01-31 14:41:28 -08:00
yungsters 5d1509e2f0 Permit non-DEV Elements in React.Children w/ DEV (#32117)
DiffTrain build for [9ff42a8798](https://github.com/facebook/react/commit/9ff42a8798863c995523e284142b47e3cdfaee80)
2025-01-30 23:04:52 -08:00
sebmarkbage 084e7f259a [Fiber] Track Appearing Named ViewTransition in the accumulateSuspenseyCommit Phase (#32254)
When a named ViewTransition component unmounts in one place and mounts
in a different place we need to match these up so we know a pair has
been created. Since the unmounts are tracked in the snapshot phase we
need some way to track the mounts before that.

Originally the way I did that is by reusing the render phase since there
was no other phase in the commit before that. However, that's not quite
correct. Just because something is visited in render doesn't mean it'll
commit. E.g. if that tree ends up suspending or erroring. Which would
lead to a false positive on match. The unmount shouldn't animate in that
case.

(Un)fortunately we have already added a traversal before the snapshot
phase for tracking suspensey CSS. The `accumulateSuspenseyCommit` phase.
This needs to find new mounts of Suspensey CSS or if there was a
reappearing Offscreen boundary it needs to find any Suspensey CSS
already inside that tree. This is exactly the same traversal we need to
find newly appearing View Transition components. So we can just reuse
that.

DiffTrain build for [4b3728f05e](https://github.com/facebook/react/commit/4b3728f05efbab9624e981339d8a0992a58f9a41)
2025-01-30 09:19:24 -08:00
sebmarkbage 3faa55f7db [Fiber] Read the class name from props.layout (#32273)
Copypasta typo.

DiffTrain build for [2fe5b572bc](https://github.com/facebook/react/commit/2fe5b572bc79c51785bcd17dd16e85427c1d2548)
2025-01-30 08:54:01 -08:00
Rubén Norte 76dc00369f Expose new method in Fabric renderer to access root instance from root tag
Differential Revision: D68767143

Pull Request resolved: https://github.com/facebook/react/pull/32272
2025-01-30 07:23:17 -08:00
dmytrorykun 4c163ed18c Use fastAddProperties in diffing (#32243)
## Summary

`fastAddProperties` has shown some perf benefits when used for creating
props payload for new components. In this PR we'll try to use it for
diffing props for existing components.

It would be good enough if it simply doesn't regress perf. We'll be able
to delete the old `addProperties`, and make `fastAddProperties` the
default behaviour.

## How did you test this change?

```
yarn lint
yarn flow native
yarn test packages/react-native-renderer -r=xplat --variant=false
yarn test packages/react-native-renderer -r=xplat --variant=true
```

DiffTrain build for [bb9a24d9fc](https://github.com/facebook/react/commit/bb9a24d9fc5faa57a85750cd3bb94546baa405ac)
2025-01-30 03:23:37 -08:00
rubennorte ace656de38 [RN] Add support for document instance in React Native (#32260)
## Summary

We're adding support for `Document` instances in React Native (as
`ReactNativeDocument` instances) in
https://github.com/facebook/react-native/pull/49012 , which requires the
React Fabric renderer to handle its lifecycle.

This modifies the renderer to create those document instances and
associate them with the React root, and provides a new method for React
Native to access them given its containerTag / rootTag.

## How did you test this change?

Tested e2e in https://github.com/facebook/react-native/pull/49012
manually syncing these changes.

DiffTrain build for [b2357ecd82](https://github.com/facebook/react/commit/b2357ecd8203341a3668a96d32d68dd519e5430d)
2025-01-29 09:14:13 -08:00
gnoff 029774ea07 [Fiber] Support Suspense boundaries anywhere (excluding hydration) (#32163)
This is a follow up to https://github.com/facebook/react/pull/32069

In the prior change I updated Fizz to allow you to render Suspense
boundaries at any level within a react-dom application by treating the
document body as the default render scope. This change updates Fiber to
provide similar semantics. Note that this update still does not deliver
hydration so unifying the Fizz and Fiber implementations in a single App
is not possible yet.

The implementation required a rework of the getHostSibling and
getHostParent algorithms. Now most HostSingletons are invisible from a
host positioning perspective. Head is special in that it is a valid host
scope so when you have Placements inside of it, it will act as the
parent. But body, and html, will not directly participate in host
positioning.

Additionally to support flipping to a fallback html, head, and body tag
in a Suspense fallback I updated the offscreen hiding/unhide logic to
pierce through singletons when lookin for matching hidable nod
boundaries anywhere (excluding hydration)

DiffTrain build for [c492f97541](https://github.com/facebook/react/commit/c492f97541486458ce21653d2669d53d380f0538)
2025-01-28 22:50:29 -08:00
sophiebits a88abd3f86 Clarify useActionState async non-transition warning (#32207)
https://github.com/facebook/react/pull/28491#issuecomment-2094861155

DiffTrain build for [b65afdd0c1](https://github.com/facebook/react/commit/b65afdd0c1f644f3630c4e8cfd9ac264c5ac329f)
2025-01-24 09:32:34 -08:00
sebmarkbage 7ab02f17cc Add Transition Types (#32105)
This adds an isomorphic API to add Transition Types, which represent the
cause, to the current Transition. This is currently mainly for View
Transitions but as a concept it's broader and we might expand it to more
features and object types in the future.

```js
import { unstable_addTransitionType as addTransitionType } from 'react';

startTransition(() => {
  addTransitionType('my-transition-type');
  setState(...);
});
```

If multiple transitions get entangled this is additive and all
Transition Types are collected. You can also add more than one type to a
Transition (hence the `add` prefix).

Transition Types are reset after each commit. Meaning that `<Suspense>`
revealing after a `startTransition` does not get any View Transition
types associated with it.

Note that the scoping rules for this is a little "wrong" in this
implementation. Ideally it would be scoped to the nearest outer
`startTransition` and grouped with any `setState` inside of it.
Including Actions. However, since we currently don't have AsyncContext
on the client, it would be too easy to drop a Transition Type if there
were no other `setState` in the same `await` task. Multiple Transitions
are entangled together anyway right now as a result. So this just tracks
a global of all pending Transition Types for the next Transition. An
inherent tricky bit with this API is that you could update multiple
roots. In that case it should ideally be associated with each root.
Transition Tracing solves this by associating a Transition with any
updates that are later collected but this suffers from the problem
mentioned above. Therefore, I just associate Transition Types with one
root - the first one to commit. Since the View Transitions across roots
are sequential anyway it kind of makes sense that only one really is the
cause and the other one is subsequent.

Transition Types can be used to apply different animations based on what
caused the Transition. You have three different ways to choose from for
how to use them:

## CSS

It integrates with [View Transition
Types](https://www.w3.org/TR/css-view-transitions-2/#active-view-transition-pseudo-examples)
so you can match different animations based on CSS scopes:

```css
:root:active-view-transition-type(my-transition-type) {
  &::view-transition-...(...) {
    ...
  }
}
```

This is kind of a PITA to write though and if you have a CSS library
that provide View Transition Classes it's difficult to import those into
these scopes.

## Class per Type

This PR also adds an object-as-map form that can be passed to all
`className` properties:

```js
<ViewTransition className={{
  'my-navigation-type': 'hello',
  'default': 'world',
}}>
```

If multiple types match, then they're joined together. If no types match
then the special `"default"` entry is used instead. If any type has the
value `"none"` then that wins and the ViewTransition is disabled (not
assigned a name).

These can be combined with `enter`/`exit`/`update`/`layout`/`share`
props to match based on kind of trigger and Transition Type.

```js
<ViewTransition enter={{
  'navigation-back': 'enter-right',
  'navigation-forward': 'enter-left',
}}
exit={{
  'navigation-back': 'exit-right',
  'navigation-forward': 'exit-left',
}}>
```

## Events

In addition, you can also observe the types in the View Transition Event
callbacks as the second argument. That way you can pick different
imperative Animations based on the cause.

```js
<ViewTransition onUpdate={(inst, types) => {
  if (types.includes('navigation-back')) {
    ...
  } else if (types.includes('navigation-forward')) {
    ...
  } else {
    ...
  }
}}>
```

## Future

In the future we might expose types to `useEffect` for more general
purpose usage. This would also allow non-View Transition based
Animations such as existing libraries to use this same feature to
coordinate the same concept.

We might also allow richer objects to be passed along here. Only the
strings would apply to View Transitions but the imperative code and
effects could do something else with them.

DiffTrain build for [028c8e6cf5](https://github.com/facebook/react/commit/028c8e6cf5ce2a87147a7e03e503ce94c7a7a0cf)
2025-01-21 12:09:38 -08:00
sebmarkbage 683d4f11e8 Fix moveBefore feature detection (#32087)
`moveBefore` was moved to the `ParentNode` mixin as per
https://github.com/whatwg/dom/pull/1307#discussion_r1881981120 _(and was
committed in
https://github.com/whatwg/dom/commit/3f3e94c5beda922962dacaeb606087f57bd7f7be)_

As a result, its existence can no longer be checked on `Node.prototype`
but must be checked in `Element.prototype`

DiffTrain build for [313c8c55de](https://github.com/facebook/react/commit/313c8c55de39cd5f009ebb033eec1666b3daa59e)
2025-01-17 08:50:46 -08:00
rickhanlonii 7784671e53 [internal] fix console patch, add RN (#32075)
The forking for `shared/ReactFeatureFlags` doesn't work in the console
patches. Since they're already forked, we can import the internal
ReactFeatureFlags files directly.

Would have caught this in testing a PR sync, but the PR syncs are broken
right now.

DiffTrain build for [43d18bc2d3](https://github.com/facebook/react/commit/43d18bc2d3d31f43706f513a996ef9b4a7495237)
2025-01-15 08:28:03 -08:00
eps1lon 4bb3447829 Use internal ReactCompilerRuntime in react/compiler-runtime entrypoint (#32054)
DiffTrain build for [6099351c76](https://github.com/facebook/react/commit/6099351c768670246e8b47e702545d03ddc97320)
2025-01-13 10:50:23 -08:00
sebmarkbage ee4a53063a View Transition Events (#32041)
This adds five events to `<ViewTransition>` that triggers when React
wants to animate it.

- `onEnter`: The `<ViewTransition>` or its parent Component is mounted
and there's no other `<ViewTransition>` with the same name being
deleted.
- `onExit`: The `<ViewTransition>` or its parent Component is unmounted
and there's no other `<ViewTransition>` with the same name being
deleted.
- `onLayout`: There are no updates to the content inside this
`<ViewTransition>` boundary itself but the boundary has resized or moved
due to other changes to siblings.
- `onShare`: This `<ViewTransition>` is being mounted and another
`<ViewTransition>` instance with the same name is being unmounted
elsewhere.
- `onUpdate`: The content of `<ViewTransition>` has changed either due
to DOM mutations or because an inner child `<ViewTransition>` has
resized.

Only one of these events is fired per Transition. If you want to cover
all updates you have to listen to `onLayout`, `onShare` and `onUpdate`.
We could potentially do something like fire `onUpdate` if `onLayout` or
`onShare` isn't specified but it's a little sketchy to have behavior
based on if someone is listening since it limits adding wrappers that
may or may not need it.

Each takes a `ViewTransitionInstance` as an argument so you don't need a
ref to animate it.

```js
<ViewTransition onEnter={inst => inst.new.animate(keyframes, options)}>
```

The timing of this event is after the View Transition's `ready` state
which means that's too late to do any changes to the View Transition's
snapshots but now both the new and old pseudo-elements are ready to
animate.

The order of `onExit` is parent first, where as the others are child
first. This mimics effect mount/unmount.

I implement this by adding to a queue in the commit phase and then call
it while we're finishing up the commit. This is after layout effects but
before passive effects since passive effects fire after the animation is
`finished`.

DiffTrain build for [540efebcc3](https://github.com/facebook/react/commit/540efebcc34357c98412a96805bfd9244d6aa678)
2025-01-12 10:24:13 -08:00
sebmarkbage c90b1c7b1e View Transition Refs (#32038)
This adds refs to View Transition that can resolve to an instance of:

```js
type ViewTransitionRef = {
  name: string,
  group: Animatable,
  imagePair: Animatable,
  old: Animatable,
  new: Animatable,
}
```

Animatable is a type that has `animate(keyframes, options)` and
`getAnimations()` on it. It's the interface that exists on Element that
lets you start animations on it. These ones are like that but for the
four pseudo-elements created by the view transition.

If a name changes, then a new ref is created. That way if you hold onto
a ref during an exit animation spawned by the name change, you can keep
calling functions on it. It will keep referring to the old name rather
than the new name.

This allows imperative control over the animations instead of using CSS
for this.

```js
const viewTransition = ref.current;
const groupAnimation = viewTransition.group.animate(keyframes, options);
const imagePairAnimation = viewTransition.imagePair.animate(keyframes, options);
const oldAnimation = viewTransition.old.animate(keyframes, options);
const newAnimation = viewTransition.new.animate(keyframes, options);
```

The downside of using this API is that it doesn't work with SSR so for
SSR rendered animations they'll fallback to the CSS. You could use this
for progressive enhancement though.

Note: In this PR the ref only controls one DOM node child but there can
be more than one DOM node in the ViewTransition fragment and they are
just left to their defaults. We could try something like making the
`animate()` function apply to multiple children but that could lead to
some weird consequences and the return value would be difficult to
merge. We could try to maintain an array of Animatable that updates with
how ever many things are currently animating but that makes the API more
complicated to use for the simple case. Conceptually this should be like
a fragment so we would ideally combine the multiple children into a
single isolate if we could. Maybe one day the same name could be applied
to multiple children to create a single isolate. For now I think I'll
just leave it like this and you're really expect to just use it with one
DOM node. If you have more than one they just get the default animations
from CSS.

Using this is a little tricky due timing. In this fixture I just use a
layout effect plus rAF to get into the right timing after the
startViewTransition is ready. In the future I'll add an event that fires
when View Transitions heuristics fire with the right timing.

DiffTrain build for [0bf1f39ec6](https://github.com/facebook/react/commit/0bf1f39ec6906c666011c0c57aa56aa34a262daf)
2025-01-10 08:59:24 -08:00