Commit Graph

1258 Commits

Author SHA1 Message Date
sebmarkbage f0a6a89dea Allow Passing Blob/File/MediaSource/MediaStream to src of <img>, <video> and <audio> (#32828)
Behind the `enableSrcObject` flag. This is revisiting a variant of what
was discussed in #11163.

Instead of supporting the [`srcObject`
property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/srcObject)
as a separate name, this adds an overload of `src` to allow objects to
be passed. The DOM needs to add separate properties for the object forms
since you read back but it doesn't make sense for React's write-only API
to do that. Similar to how we'll like add an overload for
`popoverTarget` instead of calling it `popoverTargetElement` and how
`style` accepts an object and it's not `styleObject={{...}}`.

There are a number of reason to revisit this.

- It's just way more convenient to have this built-in and it makes
conceptual sense. We typically support declarative APIs and polyfill
them when necessary.
- RSC supports Blobs and by having it built-in you don't need a Client
Component wrapper to render it where as doing it with effects would
require more complex wrappers. By picking Blobs over base64,
client-navigations can use the more optimized binary encoding in the RSC
protocol.
- The timing aspect of coordinating it with Suspensey images and image
decoding is a bit tricky to get right because if you set it in an effect
it's too late because you've already rendered it.
- SSR gets complicated when done in user space because you have to
handle both branches. Likely with `useSyncExternalStore`.
- By having it built-in we could optimize the payloads shared between
RSC payloads embedded in the HTML and data URLs.

This does not support objects for `<source src>` nor `<img srcset>`.
Those don't really have equivalents in the DOM neither. They're mainly
for picking an option when you don't know programmatically. However, for
this use case you're really better off picking a variant before
generating the blobs.

We may support Response objects in the future too as per
https://github.com/whatwg/fetch/issues/49

DiffTrain build for [ea05b750a5](https://github.com/facebook/react/commit/ea05b750a5374458fc8c74ea0918059c818d1167)
2025-04-08 09:19:00 -07:00
sebmarkbage a4e2d3cbd1 Workaround against display: inline bug in Safari (#32822)
Safari has a bug where if you put a block element inside an inline
element and the inline element has a `view-transition-name` assigned it
finds it as duplicate names.

https://bugs.webkit.org/show_bug.cgi?id=290923

This adds a warning if we detect this scenario in dev mode.

For the case where it renders into a single block, we can model this by
making the parent either `block` or `inline-block` automatically to fix
the issue. So we do that to automatically cover simple cases like
`<a><div>...</div></a>`. This unfortunately causes layout/styling thrash
so we might want to delete it once the bug has been fixed in enough
Safari versions.

DiffTrain build for [365c031fd2](https://github.com/facebook/react/commit/365c031fd2354e94248ed9390f13fe2975b994f6)
2025-04-07 07:15:32 -07:00
acdlite dc32e7cb2c [Bugfix] Infinite uDV loop in popstate event (#32821)
Found a bug that occurs during a specific combination of very subtle
implementation details.

It occurs sometimes (not always) when 1) a transition is scheduled
during a popstate event, and 2) as a result, a new value is passed to an
already-mounted useDeferredValue hook.

The fix is relatively straightforward, and I found it almost
immediately; it took a bit longer to figure out exactly how the scenario
occurred in production and create a test case to simulate it.

Rather than couple the test to the implementation details, I've chosen
to keep it as high-level as possible so that it doesn't break if the
details change. In the future, it might not be trigger the exact set of
internal circumstances anymore, but it could be useful for catching
similar bugs because it represents a realistic real world situation —
namely, switching tabs repeatedly in an app that uses useDeferredValue.

DiffTrain build for [6a7650c75c](https://github.com/facebook/react/commit/6a7650c75c1bc110517bd9b3eefdc66eadbb9cbf)
2025-04-04 21:55:17 -07:00
sebmarkbage 28c3ec94a9 Add Suspensey Images behind a Flag (#32819)
We've known we've wanted this for many years and most of the
implementation was already done for Suspensey CSS. This waits to commit
until images have decoded by default or up to 500ms timeout (same as
suspensey fonts).

It only applies to Transitions, Retries (Suspense), Gesture Transitions
(flag) and Idle (doesn't exist). Sync updates just commit immediately.

`<img loading="lazy" src="..." />` opts out since you explicitly want it
to load lazily in that case.

`<img onLoad={...} src="..." />` also opts out since that implies you're
ok with managing your own reveal.

In the future, we may add an opt in e.g. `<img blocking="render"
src="..." />` that opts into longer timeouts and re-suspends even sync
updates. Perhaps also triggering error boundaries on errors.

The rollout for this would have to go in a major and we may have to
relax the default timeout to not delay too much by default. However, we
can also make this part of `enableViewTransition` so that if you opt-in
by using View Transitions then those animations will suspend on images.
That we could ship in a minor.

DiffTrain build for [efb22d8850](https://github.com/facebook/react/commit/efb22d8850382c3b53c1b2b8d22036d7e6cc9488)
2025-04-04 12:00:08 -07:00
sebmarkbage 7e5dab9fe1 Fix Bugs Measuring Performance Track for Effects (#32815)
This fixes two bugs with commit phase effect tracking.

I missed, or messed up the rebase for, deletion effects when a subtree
was deleted and for passive disconnects when a subtree was hidden.

The other bug is that when I started using self time
(componentEffectDuration) for color and for determining whether to
bother logging an entry, I didn't consider that the component with
effects can have children which end up resetting this duration before we
log. Which lead to most effects not having their components logged since
they almost always have children.

We don't necessarily have to push/pop but we have to store at least one
thing on the stack unfortunately. That's because we have to do the
actual log after the children to get the right end time. So might as
well use the push/pop strategy like the rest of them.

DiffTrain build for [c0f08ae74a](https://github.com/facebook/react/commit/c0f08ae74a46686f5718e9e6c511d27419fd632c)
2025-04-03 20:40:11 -07:00
sebmarkbage 00e3f22c1a Don't shadow EventListenerOptionsOrUseCapture and FocusOptions types (#32801)
These are built-in to Flow.

DiffTrain build for [7a728dffd1](https://github.com/facebook/react/commit/7a728dffd14550cd22e6d8b8514e82435bbeba76)
2025-04-01 11:29:17 -07:00
sebmarkbage 67628e7676 Warn if addTransitionType is called when there are no pending Actions (#32793)
Stacked on #32792.

It's tricky to associate a specific `addTransitionType` call to a
specific `startTransition` call because we don't have `AsyncContext` in
browsers yet. However, we can keep track if there are any async
transitions running at all, and if not, warn. This should cover most
cases.

This also errors when inside a React render which might be a legit way
to associate a Transition Type to a specific render (e.g. based on props
changing) but we want to be a more conservative about allowing that yet.
If we wanted to support calling it in render, we might want to set which
Transition object is currently rendering but it's still tricky if the
render has `async function` components. So it might at least be
restricted to sync components (like Hooks).

DiffTrain build for [deca96520f](https://github.com/facebook/react/commit/deca96520f1e9e804b0e5b0d81563327d9c55521)
2025-04-01 09:28:47 -07:00
sebmarkbage 70814b1b24 Add startGestureTransition API (#32785)
Stacked on #32783. This will replace [the `useSwipeTransition`
API](https://github.com/facebook/react/pull/32373).

Instead, of a special Hook, you can make updates to `useOptimistic`
Hooks within the `startGestureTransition` scope.

```
import {unstable_startGestureTransition as startGestureTransition} from 'react';

const cancel = startGestureTransition(timeline, () => {
  setOptimistic(...);
}, options);
```

There are some downsides to this like you can't define two directions as
once and there's no "standard" direction protocol. It's instead up to
libraries to come up with their own conventions (although we can suggest
some).

The convention is still that a gesture recognizer has two props `action`
and `gesture`. The `gesture` prop is a Gesture concept which now behaves
more like an Action but 1) it can't be async 2) it shouldn't have
side-effects. For example you can't call `setState()` in it except on
`useOptimistic` since those can be reverted if needed. The `action` is
invoked with whatever side-effects you want after the gesture fulfills.

This is isomorphic and not associated with a specific renderer nor root
so it's a bit more complicated.

To implement this I unify with the `ReactSharedInternal.T` property to
contain a regular Transition or a Gesture Transition (the `gesture`
field). The benefit of this unification means that every time we
override this based on some scope like entering `flushSync` we also
override the `startGestureTransition` scope. We just have to be careful
when we read it to check the `gesture` field to know which one it is.
(E.g. I error for setState / requestFormReset.)

The other thing that's unique is the `cancel` return value to know when
to stop the gesture. That cancellation is no longer associated with any
particular Hook. It's more associated with the scope of the
`startGestureTransition`. Since the schedule of whether a particular
gesture has rendered or committed is associated with a root, we need to
somehow associate any scheduled gestures with a root.

We could track which roots we update inside the scope but instead, I
went with a model where I check all the roots and see if there's a
scheduled gesture matching the timeline. This means that you could
"retain" a gesture across roots. Meaning this wouldn't cancel until both
are cancelled:

```
const cancelA = startGestureTransition(timeline, () => {
  setOptimisticOnRootA(...);
}, options);

const cancelB = startGestureTransition(timeline, () => {
  setOptimisticOnRootB(...);
}, options);
```

It's more like it's a global transition than associated with the roots
that were updated.

Optimistic updates mostly just work but I now associate them with a
specific "ScheduledGesture" instance since we can only render one at a
time and so if it's not the current one, we leave it for later.

Clean up of optimistic updates is now lazy rather than when we cancel.
Allowing the cancel closure not to have to be associated with each
particular update.

DiffTrain build for [b286430c8a](https://github.com/facebook/react/commit/b286430c8a585dc2e2e3cc023e7c455ec2b34ab7)
2025-03-31 17:17:22 -07:00
sebmarkbage f8bbdb7c32 Unify BatchConfigTransition and Transition types (#32783)
This is some overdue refactoring. The two types never made sense. It
also should be defined by isomorphic since it defines how it should be
used by renderers rather than isomorphic depending on Fiber.

Clean up hidden classes to be consistent.

Fix missing name due to wrong types. I choose not to invoke the
transition tracing callbacks if there's no name since the name is
required there.

DiffTrain build for [d3b8ff6e58](https://github.com/facebook/react/commit/d3b8ff6e589bcacfd1c9b0aa48c42fd1c93001c1)
2025-03-31 17:05:59 -07:00
rickhanlonii bea1002a4f s/HTML/text for text hydration mismatches (#32763)
DiffTrain build for [3e88e97c11](https://github.com/facebook/react/commit/3e88e97c116c7a1535976f2d4486bbf345476443)
2025-03-26 14:46:01 -07:00
sebmarkbage a28916b5dd Don't flush synchronous work if we're in the middle of a ViewTransition async sequence (#32760)
Starting a View Transition is an async sequence. Since React can get a
sync update in the middle of sequence we sometimes interrupt that
sequence.

Currently, we don't actually cancel the View Transition so it can just
run as a partial. This ensures that we fully skip it when that happens,
as well as warn.

However, it's very easy to trigger this with just a setState in
useLayoutEffect right now. Therefore if we're inside the preparing
sequence of a startViewTransition, this delays work that would've
normally flushed in a microtask. ~Maybe we want to do the same for
Default work already scheduled through a scheduler Task.~ Edit: This was
already done.

`flushSync` currently will still lead to an interrupted View Transition
(with a warning). There's a tradeoff here whether we want to try our
best to preserve the guarantees of `flushSync` or favor the animation.
It's already possible to suspend at the root with `flushSync` which
means it's not always 100% guaranteed to commit anyway. We could treat
it as suspended. But let's see how much this is a problem in practice.

DiffTrain build for [a5297ece62](https://github.com/facebook/react/commit/a5297ece6217f5495cbe38ba58f928b2697b0f99)
2025-03-26 11:50:54 -07:00
poteto 0c4df01e80 [crud] Revert CRUD overload (#32741)
Cleans up this experiment. After some internal experimentation we are
deprioritizing this project for now and may revisit it at a later point.

DiffTrain build for [313332d111](https://github.com/facebook/react/commit/313332d111a2fba2db94c584334d8895e8d73c61)
2025-03-26 09:16:06 -07:00
jackpope 9477f11aa2 Fix ownerStackLimit feature gating for tests (#32726)
https://github.com/facebook/react/pull/32529 added a dynamic flag for
this, but that breaks tests since the flags are not defined everywhere.

However, this is a static value and the flag is only for supporting
existing tests. So we can override it in the test config, and make it
static at built time instead.

DiffTrain build for [f99c9feaf7](https://github.com/facebook/react/commit/f99c9feaf786fbdad0ad8d2d81196a247302dd3c)
2025-03-26 09:09:26 -07:00
SamChou19815 19714aa0d5 [flow] Replace $PropertyType with indexed access type in ReactNativeTypes (#32733)
DiffTrain build for [b59f186011](https://github.com/facebook/react/commit/b59f18601179bb06a2c32a76547fd4929aa1ce9c)
2025-03-24 20:06:45 -07:00
eps1lon 8b3404306d Stop creating Owner Stacks if many have been created recently (#32529)
Co-authored-by: Jack Pope <jackpope1@gmail.com>

DiffTrain build for [4a9df08157](https://github.com/facebook/react/commit/4a9df08157f001c01b078d259748512211233dcf)
2025-03-23 15:53:15 -07:00
poteto 7c8cabc1cf [ci] Add missing permissions to runtime_commit_artifacts.yml (#32710)
Turns out we need permissions to write to `contents` after all.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32710).
* #32711
* __->__ #32710

DiffTrain build for [de4aad5ba6](https://github.com/facebook/react/commit/de4aad5ba693be099b215b5819b5f25d05051a84)
2025-03-21 15:07:21 -07:00
rickhanlonii 8a468f1a72 [refactor] move isValidElementType to react-is (#32518)
DiffTrain build for [b630219b13](https://github.com/facebook/react/commit/b630219b1377f3117036b1c6118676c16fdb21b7)
2025-03-20 14:01:27 -07:00
poteto 1f072d9af9 [ci] Fix Will commit these changes www step (#32681)
Unlike the fbsource version of the step, www doesn't add any changes so
the `force` input doesn't actually work

DiffTrain build for [ff8f6f21f7](https://github.com/facebook/react/commit/ff8f6f21f756c81fba284557357eb6e6ce765149)
2025-03-19 15:38:03 -07:00
poteto af02928d40 [ci] Properly format commit message take 2 (#32673)
We need to use the commit message from `main`, not the builds branch

DiffTrain build for [b0446ff06a](https://github.com/facebook/react/commit/b0446ff06a484127412638c2be9a0382c6f3a84b)
2025-03-19 11:19:28 -07:00
sebmarkbage 861b14904a Measure Updated ViewTransition Boundaries (#32653)
This does the same thing for  that we did
for  in
https://github.com/facebook/react/pull/32612/commits/e3cbaffef05c7b476c07f7495e06788a9503e636.
If a boundary hasn't mutated and didn't change in size, we mark it for
cancellation. Otherwise we add names to it. The different from the
CommitViewTransition path is that the old names are added to the
clones so this is the first time the new names.

Now we also cancel any boundaries that were unchanged. So now the root
no longer animates. We still have to clone them. There are other
optimizations that can avoid cloning but once we've done all the layouts
we can still cancel the running animation and let them just be the
regular content if they didn't change. Just like the regular
fire-and-forget path.

This also fixes the measurement so that we measure clones by adjusting
their position back into the viewport.

This actually surfaces a bug in Safari that was already in #32612. It
turns out that the old names aren't picked up for some reason and so in
Safari they looked more like a cross-fade than what #32612 was supposed
to fix. However, now that bug is even more apparent because they
actually just disappear in Safari. I'm not sure what that bug is but
it's unrelated to this PR so will fix that separately.

DiffTrain build for [3c3696d554](https://github.com/facebook/react/commit/3c3696d5548c8a67f2332fd78332b9366abaf2f9)
2025-03-17 18:45:36 -07:00
rickhanlonii cfa201d0ae [bug] Fix component name for Portal and add tests (#32640)
Based off: https://github.com/facebook/react/pull/32499

While looking into `React.lazy` issues for built-ins, I noticed we
already error for `lazy` with build-ins, but we don't have any tests for
`getComponentNameFromType` using all the built-ins. This may be
something we should handle, but for now we should at least have tests.

Here's why: while writing tests, I noticed we check `type` instead of
`$$typeof` for portals:

https://github.com/facebook/react/blob/9cdf8a99edcfd94d7420835ea663edca04237527/packages/react-reconciler/src/ReactPortal.js#L25-L32

This PR adds tests for all the built-ins and fixes the portal bug.

[Commit to
review](https://github.com/facebook/react/pull/32640/commits/e068c167d48d4df01e79db8f13276bb46d7ab439)

DiffTrain build for [8243f3f063](https://github.com/facebook/react/commit/8243f3f0631698e819c690710a7f18f767068981)
2025-03-17 08:30:28 -07:00
rickhanlonii 58d48f556d Remove offscreen type (#32639)
Based off https://github.com/facebook/react/pull/32499

This is no longer used.

[Review
commit](https://github.com/facebook/react/commit/88c297d12f8b2562be3982fba867f03a137551cb)

DiffTrain build for [df31952275](https://github.com/facebook/react/commit/df319522758b7fdfed3ddfa517cc1cc298ef1602)
2025-03-17 06:44:18 -07:00
rickhanlonii e4b2c5b29a [refactor] Add element type for Activity (#32499)
This PR separates Activity to it's own element type separate from
Offscreen. The goal is to allow us to add Activity element boundary
semantics during hydration similar to Suspense semantics, without
impacting the Offscreen behavior in suspended children.

DiffTrain build for [1a191701fe](https://github.com/facebook/react/commit/1a191701fe5000098d23328b2ea9d70457fea1f8)
2025-03-17 06:27:19 -07:00
sebmarkbage 025e752e40 Add more phases to the ReactFiberApplyGesture (#32578)
Stacked on #32585 and #32605.

This adds more loops for the phases of "Apply Gesture". It doesn't
implement the interesting bit yet like adding view-transition-names and
measurements. I'll do that in a separate PR to keep reviewing easier.

The three phases of this approach is roughly:

- Clone and apply names to the "old" state.
- Inside startViewTransition: Apply names to the "new" state. Measure
both the "old" and "new" state to know whether to cancel some of them.
Delete the clones which will include all the "old" names.
- After startViewTransition: Restore "new" names back to no
view-transition-name.

Since we don't have any other Effects in these phases we have a bit more
flexibility and we can avoid extra phases that traverse the tree. I've
tried to avoid any additional passes.

An interesting consequence of this approach is that we could measure
both the "old" and "new" state before `startViewTransition`. This would
be more efficient because we wouldn't need to take View Transition
snapshots of parts of the tree that won't actually animate. However,
that would require an extra pass and force layout earlier. It would also
have different semantics from the fire-and-forget View Transitions
because we could optimize better which can be visible. It would also not
account for any late mutations. So I decided to instead let the layout
be computed by painting as usual and then measure both "old" and "new"
inside the startViewTransition instead. Then canceling anything that
doesn't animate to keep it consistent.

Unfortunately, though there's not a lot of code sharing possible in
these phases because the strategy is so different with the cloning and
because the animation is performed in reverse. The "finishedWork" Fiber
represents the "old" state and the "current" Fiber represents the "new"
state.

The most complicated phase is the cloning. I actually ended up having to
make a very different pattern from the other phases and CommitWork in
general. Because we have to clone as we go and also do other things like
apply names and finding pairs, it has more phases. I ended up with an
approach that uses three different loops. The outer one for updated
trees, one for inserted trees that don't need cloning (doesn't include
reappearing offscreen) and one for not updated trees that still need
cloning. Inside each loop it can also be in different phases which I
track with the `visitPhase` enum - this pattern is kind of new.

Additionally, we need to measure the cloned nodes after we've applied
mutations to them and we have to wait until the whole tree is inserted.
We don't have a reference to these DOM elements in the Fiber tree since
that still refers to the original ones. We need to store the cloned
elements somewhere. So I added a temporary field on the
ViewTransitionState to keep track of any clones owned by that
ViewTransition.

When we deep clone an unchanged subtree we don't have DOM element
instances. It wouldn't be quite safe to try to find them from the tree
structure. So we need to avoid the deep clones if we might need DOM
elements. Therefore we keep traversing in the case where we need to find
nested ViewTransition boundaries that are either potentially affected by
layout or a "pair".

For the other two phases the pattern there's a lot of code duplication
since it's slightly different from the commit ones but they at least
follow the same pattern. For the restore phase I was actually able to
reuse most of the code.

I don't love how much code this is.

DiffTrain build for [c4a3b92e09](https://github.com/facebook/react/commit/c4a3b92e098cf1896939758e7419cbdb0e2f0cf4)
2025-03-14 10:28:49 -07:00
sebmarkbage 58c68bafca Gate flushGestureMutations and flushGestureAnimations (#32605)
Normally these are gated by the whole commitGestureOnRoot path but in
the case of an early commit these phases may need to be invoked.
Earlier. Those paths weren't gated which I noticed when I started adding
code to them.

DiffTrain build for [3e956805e8](https://github.com/facebook/react/commit/3e956805e899bff7aea7b19c56e6adaf362cdc2b)
2025-03-14 10:27:08 -07:00
poteto acc3720f55 feat(eslint-plugin-react-hooks): merge rule from eslint-plugin-react-compiler into react-hooks plugin (#32416)
This change merges the `react-compiler` rule from
`eslint-plugin-react-compiler` into the `eslint-plugin-react-hooks`
plugin. In order to do the move in a way that keeps commit history with
the moved files, but also no remove them from their origin until a
future cleanup change can be done, I did the `git mv` first, and then
recreated the files that were moved in their original places, as a
separate commit. Unfortunately GH shows the moved files as new instead
of the ones that are truly new. But in the IDE and `git blame`, commit
history is intact with the moved files.

Since this change adds new dependencies, and one of those dependencies
has a higher `engines` declaration for `node` than what the plugin
currently has, this is technically a breaking change and will have to go
out as part of a major release.

### Related Changes
- https://github.com/facebook/react/pull/32458

---------

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

DiffTrain build for [5ccfcd17ff](https://github.com/facebook/react/commit/5ccfcd17ffa0adf9e7f5ba7fbf48e6bf6a4eb67e)
2025-03-12 18:53:50 -07:00
poteto 0f058a31fe Update babel configs used in jest (#32588)
Extracting portions of #32416 for easier review.

This PR updates our babel configs (only used in jest) to support
classes.

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32588).
* #32592
* #32591
* #32590
* #32589
* __->__ #32588

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>

DiffTrain build for [f695f95290](https://github.com/facebook/react/commit/f695f95290aa3560a00e8a3b617205ac9e087e0e)
2025-03-12 16:18:21 -07:00
jackpope 0f346a4282 Add ref to Fragment (#32465)
*This API is experimental and subject to change or removal.*

This PR is an alternative to
https://github.com/facebook/react/pull/32421 based on feedback:
https://github.com/facebook/react/pull/32421#pullrequestreview-2625382015
. The difference here is that we traverse from the Fragment's fiber at
operation time instead of keeping a set of children on the
`FragmentInstance`. We still need to handle newly added or removed child
nodes to apply event listeners and observers, so we treat those updates
as effects.

**Fragment Refs**

This PR extends React's Fragment component to accept a `ref` prop. The
Fragment's ref will attach to a custom host instance, which will provide
an Element-like API for working with the Fragment's host parent and host
children.

Here I've implemented `addEventListener`, `removeEventListener`, and
`focus` to get started but we'll be iterating on this by adding
additional APIs in future PRs. This sets up the mechanism to attach refs
and perform operations on children. The FragmentInstance is implemented
in `react-dom` here but is planned for Fabric as well.

The API works by targeting the first level of host children and proxying
Element-like APIs to allow developers to manage groups of elements or
elements that cannot be easily accessed such as from a third-party
library or deep in a tree of Functional Component wrappers.

```javascript
import {Fragment, useRef} from 'react';

const fragmentRef = useRef(null);

<Fragment ref={fragmentRef}>
  <div id="A" />
  <Wrapper>
    <div id="B">
      <div id="C" />
    </div>
  </Wrapper>
  <div id="D" />
</Fragment>
```

In this case, calling `fragmentRef.current.addEventListener()` would
apply an event listener to `A`, `B`, and `D`. `C` is skipped because it
is nested under the first level of Host Component. If another Host
Component was appended as a sibling to `A`, `B`, or `D`, the event
listener would be applied to that element as well and any other APIs
would also affect the newly added child.

This is an implementation of the basic feature as a starting point for
feedback and further iteration.

DiffTrain build for [6aa8254bb7](https://github.com/facebook/react/commit/6aa8254bb7353fe3096289edc669cf168e9fd190)
2025-03-12 07:38:22 -07:00
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