This enables `focus` and `focusLast` methods on FragmentInstances to
search nested host components, depth first. Attempts focus on each child
and bails if one is successful. Previously, only the first level of host
children would attempt focus.
Now if we have an example like
```
component MenuItem() {
return (<div><a>{...}</a></div>)
}
component Menu() {
return <Fragment>{items.map(i => <MenuItem i={i} />)}</Fragment>
}
```
We can target focus on the first or last a tag, rather than checking
each wrapping div and then noop.
This adds `compareDocumentPosition(otherNode)` to fragment instances.
The semantics implemented are meant to match typical element
positioning, with some fragment specifics. See the unit tests for all
expectations.
- An element preceding a fragment is `Node.DOCUMENT_POSITION_PRECEDING`
- An element after a fragment is `Node.DOCUMENT_POSITION_FOLLOWING`
- An element containing the fragment is
`Node.DOCUMENT_POSITION_PRECEDING` and
`Node.DOCUMENT_POSITION_CONTAINING`
- An element within the fragment is
`Node.DOCUMENT_POSITION_CONTAINED_BY`
- An element compared against an empty fragment will result in
`Node.DOCUMENT_POSITION_DISCONNECTED` and
`Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC`
Since we assume a fragment instances target children are DOM siblings
and we want to compare the full fragment as a pseudo container, we can
compare against the first target child outside of handling the special
cases (empty fragments and contained elements).
Adds Fragment Ref support to RN through the Fabric config, starting with
`observeUsing`/`unobserveUsing`. This is mostly a copy from the
implementation on DOM, and some of it can likely be shared in the future
but keeping it separate for now and we can refactor as we add more
features.
Added a basic test with Fabric, but testing specific methods requires so
much mocking that it doesn't seem valuable here.
I built Fabric and ran on the Catalyst app internally to test with
intersection observers end to end.
Stacked on #32862 and #32842.
This means that Activity boundaries now act as boundaries which can have
their effects mounted independently. Just like Suspense boundaries, we
hydrate the outer content first and then start hydrating the content in
an Offscreen lane. Flowing props or interacting with the content
increases the priority just like Suspense boundaries.
This skips emitting even the comments for `<Activity mode="hidden">` so
we don't hydrate those. Instead those are deferred to a later client
render.
The implementation are just forked copies of the SuspenseComponent
branches and then carefully going through each line and tweaking it.
The main interesting bit is that, unlike Suspense, Activity boundaries
don't have fallbacks so all those branches where you might commit a
suspended tree disappears. Instead, if something suspends while
hydration, we can just leave the dehydrated content in place. However,
if something does suspend during client rendering then it should bubble
up to the parent. Therefore, we have to be careful to only
pushSuspenseHandler when hydrating. That's really the main difference.
This just uses the existing basic Activity tests but I've started work
on port all of the applicable Suspense tests in SelectiveHydration-test
and PartialHydration-test to Activity versions.
Stacked on #32851 and #32900.
This implements the equivalent Configs for ActivityInstance as we have
for SuspenseInstance. These can be implemented as comments but they
don't have to be and can be implemented differently in the renderer.
This seems like a lot duplication but it's actually ends mostly just
calling the same methods underneath and the wrappers compiles out.
This doesn't leave the Activity dehydrated yet. It just hydrates into it
immediately.
This implements `getRootNode(options)` on fragment instances as the
equivalent of calling `getRootNode` on the fragment's parent host node.
The parent host instance will also be used to proxy dispatchEvent in an
upcoming PR.
`focus()` was added in https://github.com/facebook/react/pull/32465.
Here we add `focusLast()` and `blur()`. I also extended `focus` to take
options.
`focus` will focus the first focusable element. `focusLast` will focus
the last focusable element. We could consider a `focusFirst` naming or
even the `focusWithin` used by test selector APIs as well.
`blur` will only have an effect if the current `document.activeElement`
is one of the fragment children.
This is a nit but a Config should not have to know anything about the
internals of Fibers. Ideally it shouldn't even access them but we have
some cases where we need pointers back in like for this fragment.
The way we've typically abstracted this is using the
`ReactFiberTreeReflection` helper that's in the `react-reconciler`. Such
as in the event system.
https://github.com/facebook/react/blob/f3c956006a90dc68210bd3e19497d10fb9b028d3/packages/react-dom-bindings/src/events/ReactDOMEventListener.js#L22-L26
We sometimes cheat but we really should clean this up such that a
`Fiber` is actually an opaque type to the Configs and it can never dot
into it without using a helper.
So this just moves `traverseFragmentInstanceChildren` to
ReactFiberTreeReflection so that the ConfigDOM doesn't ever dot into its
fields itself. It just passes the Fiber through back into the
react-reconciler. I had to add a wrapper to read the `.child` to avoid
that being assumed too. I also noticed that FragmentInstanceType is not
actually passed through so that argument is unnecessary.
The public API has been deleted a long time ago so this should be unused
unless it's used by hacks. It should be replaced with an
effect/lifecycle that manually tracks this if you need it.
The problem with this API is how the timing implemented because it
requires Placement/Hydration flags to be cleared too early. In fact,
that's why we also have a separate PlacementDEV flag that works
differently.
https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberCommitWork.js#L2157-L2165
We should be able to remove this code now.
We previously had two slightly different concepts for "current fiber".
There's the "owner" which is set inside of class components in prod if
string refs are enabled, and sometimes inside function components in DEV
but not other contexts.
Then we have the "current fiber" which is only set in DEV for various
warnings but is enabled in a bunch of contexts.
This unifies them into a single "current fiber".
The concept of string refs shouldn't really exist so this should really
be a DEV only concept. In the meantime, this sets the current fiber
inside class render only in prod, however, in DEV it's now enabled in
more contexts which can affect the string refs. That was already the
case that a string ref in a Function component was only connecting to
the owner in prod. Any string ref associated with any non-class won't
work regardless so that's not an issue. The practical change here is
that an element with a string ref created inside a life-cycle associated
with a class will work in DEV but not in prod. Since we need the current
fiber to be available in more contexts in DEV for the debugging
purposes. That wouldn't affect any old code since it would have a broken
ref anyway. New code shouldn't use string refs anyway.
The other implication is that "owner" doesn't necessarily mean
"rendering" since we need the "owner" to track other debug information
like stacks - in other contexts like useEffect, life cycles, etc.
Internally we have a separate `isRendering` flag that actually means
we're rendering but even that is a very overloaded concept. So anything
that uses "owner" to imply rendering might be wrong with this change.
This is a first step to a larger refactor for tracking current rendering
information.
---------
Co-authored-by: Sebastian Silbermann <silbermann.sebastian@gmail.com>
Rebasing and landing https://github.com/facebook/react/pull/28798
This PR was approved already but held back to give time for the sync.
Rebased and landing here without pushing to seb's remote to avoid
possibility of lost updates
---------
Co-authored-by: Sebastian Markbage <sebastian@calyptus.eu>
This is similar to #28771 but for isomorphic. We need a make over for
these dispatchers anyway so this is the first step. Also helps flush out
some internals usage that will break anyway.
It flattens the inner mutable objects onto the ReactSharedInternals.
part of https://github.com/facebook/react/pull/26571
merging separately to improve tracking of files renames in git
Rename HostConfig files to FiberConfig to clarify they are configs for
Fiber and not Fizz/Flight. This better conforms to the naming used in
Flight and now Fizz of `ReactFlightServerConfig` and `ReactFizzConfig`
## Hoistables
In the original implementation of Float, all hoisted elements were
treated like Resources. They had deduplication semantics and hydrated
based on a key. This made certain kinds of hoists very challenging such
as sequences of meta tags for `og:image:...` metadata. The reason is
each tag along is not dedupable based on only it's intrinsic properties.
two identical tags may need to be included and hoisted together with
preceding meta tags that describe a semantic object with a linear set of
html nodes.
It was clear that the concept of Browser Resources (stylesheets /
scripts / preloads) did not extend universally to all hositable tags
(title, meta, other links, etc...)
Additionally while Resources benefit from deduping they suffer an
inability to update because while we may have multiple rendered elements
that refer to a single Resource it isn't unambiguous which element owns
the props on the underlying resource. We could try merging props, but
that is still really hard to reason about for authors. Instead we
restrict Resource semantics to freezing the props at the time the
Resource is first constructed and warn if you attempt to render the same
Resource with different props via another rendered element or by
updating an existing element for that Resource.
This lack of updating restriction is however way more extreme than
necessary for instances that get hoisted but otherwise do not dedupe;
where there is a well defined DOM instance for each rendered element. We
should be able to update props on these instances.
Hoistable is a generalization of what Float tries to model for hoisting.
Instead of assuming every hoistable element is a Resource we now have
two distinct categories, hoistable elements and hoistable resources. As
one might guess the former has semantics that match regular Host
Components except the placement of the node is usually in the <head>.
The latter continues to behave how the original implementation of
HostResource behaved with the first iteration of Float
### Hoistable Element
On the server hoistable elements render just like regular tags except
the output is stored in special queues that can be emitted in the stream
earlier than they otherwise would be if rendered in place. This also
allow for instance the ability to render a hoistable before even
rendering the <html> tag because the queues for hoistable elements won't
flush until after we have flushed the preamble (`<DOCTYPE
html><html><head>`).
On the client, hoistable elements largely operate like HostComponents.
The most notable difference is in the hydration strategy. If we are
hydrating and encounter a hoistable element we will look for all tags in
the document that could potentially be a match and we check whether the
attributes match the props for this particular instance. We also do this
in the commit phase rather than the render phase. The reason hydration
can be done for HostComponents in render is the instance will be removed
from the document if hydration fails so mutating it in render is safe.
For hoistables the nodes are not in a hydration boundary (Root or
SuspenseBoundary at time of writing) and thus if hydration fails and we
may have an instance marked as bound to some Fiber when that Fiber never
commits. Moving the hydration matching to commit ensures we will always
succeed in pairing the hoisted DOM instance with a Fiber that has
committed.
### Hoistable Resource
On the server and client the semantics of Resources are largely the same
they just don't apply to title, meta, and most link tags anymore.
Resources hoist and dedupe via an `href` key and are ref counted. In a
future update we will add a garbage collector so we can clean up
Resources that no longer have any references
## `<style>` support
In earlier implementations there was no support for <style> tags. This
PR adds support for treating `<style href="..."
precedence="...">...</style>` as a Resource analagous to `<link
rel="stylesheet" href="..." precedence="..." />`
It may seem odd at first to require an href to get Resource semantics
for a style tag. The rationale is that these are for inlining of actual
external stylesheets as an optimization and for URI like scoping of
inline styles for css-in-js libraries. The href indicates that the key
space for `<style>` and `<link rel="stylesheet" />` Resources is shared.
and the precedence is there to allow for interleaving of both kinds of
Style resources. This is an advanced feature that we do not expect most
app developers to use directly but will be quite handy for various
styling libraries and for folks who want to inline as much as possible
once Fizz supports this feature.
## refactor notes
* HostResource Fiber type is renamed HostHoistable to reflect the
generalization of the concept
* The Resource object representation is modified to reduce hidden class
checks and to use less memory overall
* The thing that distinguishes a resource from an element is whether the
Fiber has a memoizedState. If it does, it will use resource semantics,
otherwise element semantics
* The time complexity of matching hositable elements for hydration
should be improved
This setting is an incremental path to the next Flow version enforcing
type annotations on most functions (except some inline callbacks).
Used
```
node_modules/.bin/flow codemod annotate-functions-and-classes --write .
```
to add a majority of the types with some hand cleanup when for large
inferred objects that should just be `Fiber` or weird constructs
including `any`.
Suppressed the remaining issues.
Builds on #25918
We've heard from multiple contributors that the Reconciler forking
mechanism was confusing and/or annoying to deal with. Since it's
currently unused and there's no immediate plans to start using it again,
this removes the forking.
Fully removing the fork is split into 2 steps to preserve file history:
**#25774 previous PR that did the bulk of the work:**
- remove `enableNewReconciler` feature flag.
- remove `unstable_isNewReconciler` export
- remove eslint rules for cross fork imports
- remove `*.new.js` files and update imports
- merge non-suffixed files into `*.old` files where both exist
(sometimes types were defined there)
**This PR**
- rename `*.old` files
* Facebook -> Meta in copyright
rg --files | xargs sed -i 's#Copyright (c) Facebook, Inc. and its affiliates.#Copyright (c) Meta Platforms, Inc. and affiliates.#g'
* Manual tweaks
* [Fizz/Float] Float for stylesheet resources
This commit implements Float in Fizz and on the Client. The initial set of supported APIs is roughly
1. Convert certain stylesheets into style Resources when opting in with precedence prop
2. Emit preloads for stylesheets and explicit preload tags
3. Dedupe all Resources by href
4. Implement ReactDOM.preload() to allow for imperative preloading
5. Implement ReactDOM.preinit() to allow for imperative preinitialization
Currently supports
1. style Resources (link rel "stylesheet")
2. font Resources (preload as "font")
later updates will include support for scripts and modules
* Hoist error codes import to module scope
When this code was written, the error codes map (`codes.json`) was
created on-the-fly, so we had to lazily require from inside the visitor.
Because `codes.json` is now checked into source, we can import it a
single time in module scope.
* Minify error constructors in production
We use a script to minify our error messages in production. Each message
is assigned an error code, defined in `scripts/error-codes/codes.json`.
Then our build script replaces the messages with a link to our
error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92
This enables us to write helpful error messages without increasing the
bundle size.
Right now, the script only works for `invariant` calls. It does not work
if you throw an Error object. This is an old Facebookism that we don't
really need, other than the fact that our error minification script
relies on it.
So, I've updated the script to minify error constructors, too:
Input:
Error(`A ${adj} message that contains ${noun}`);
Output:
Error(formatProdErrorMessage(ERR_CODE, adj, noun));
It only works for constructors that are literally named Error, though we
could add support for other names, too.
As a next step, I will add a lint rule to enforce that errors written
this way must have a corresponding error code.
* Minify "no fallback UI specified" error in prod
This error message wasn't being minified because it doesn't use
invariant. The reason it didn't use invariant is because this particular
error is created without begin thrown — it doesn't need to be thrown
because it's located inside the error handling part of the runtime.
Now that the error minification script supports Error constructors, we
can minify it by assigning it a production error code in
`scripts/error-codes/codes.json`.
To support the use of Error constructors more generally, I will add a
lint rule that enforces each message has a corresponding error code.
* Lint rule to detect unminified errors
Adds a lint rule that detects when an Error constructor is used without
a corresponding production error code.
We already have this for `invariant`, but not for regular errors, i.e.
`throw new Error(msg)`. There's also nothing that enforces the use of
`invariant` besides convention.
There are some packages where we don't care to minify errors. These are
packages that run in environments where bundle size is not a concern,
like react-pg. I added an override in the ESLint config to ignore these.
* Temporarily add invariant codemod script
I'm adding this codemod to the repo temporarily, but I'll revert it
in the same PR. That way we don't have to check it in but it's still
accessible (via the PR) if we need it later.
* [Automated] Codemod invariant -> Error
This commit contains only automated changes:
npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*"
yarn linc --fix
yarn prettier
I will do any manual touch ups in separate commits so they're easier
to review.
* Remove temporary codemod script
This reverts the codemod script and ESLint config I added temporarily
in order to perform the invariant codemod.
* Manual touch ups
A few manual changes I made after the codemod ran.
* Enable error code transform per package
Currently we're not consistent about which packages should have their
errors minified in production and which ones should.
This adds a field to the bundle configuration to control whether to
apply the transform. We should decide what the criteria is going
forward. I think it's probably a good idea to minify any package that
gets sent over the network. So yes to modules that run in the browser,
and no to modules that run on the server and during development only.
The last step of the `findDOMNode` algorithm is a search of the
current tree.
When descending into a child node, it mutates `child.return` so that it
points to the current fiber pair, instead of a work-in-progress. This
can cause bugs if `findDOMNode` is called at the wrong time, like in
an interleaved event.
For this reason (among others), you're not suppposed to use
`findDOMNode` in Concurrent Mode. However, we still have some internal
uses that we haven't migrated.
To reduce the potential for bugs, I've removed the `.return` pointer
assignment in favor of recursion.
* Failing test: Infinite loop in beforeblur event
If the focused node is hidden by a Suspense boundary, we fire the
beforeblur event. Our check for whether a tree is being hidden isn't
specific enough. It should only fire when the tree is initially hidden,
but it's being fired for updates, too.
* Only fire beforeblur on visible -> hidden
Should only beforeblur fire if the node was previously visible. Not
during updates to an already hidden tree.
To optimize this, we should use a dedicated effect tag and mark it in
the render phase. I've left this for a follow-up, though. Maybe can
revisit after the planned refactor of the commit phase.
* Move logic to commit phase
isFiberSuspenseAndTimedOut is used elsewhere, so I inlined the commit
logic into the commit phase itself.
Some of our internal reconciler types have leaked into other packages.
Usually, these types are treated as opaque; we don't read and write
to its fields. This is good.
However, the type is often passed back to a reconciler method. For
example, React DOM creates a FiberRoot with `createContainer`, then
passes that root to `updateContainer`. It doesn't do anything with the
root except pass it through, but because `updateContainer` expects a
full FiberRoot, React DOM is still coupled to all its fields.
I don't know if there's an idiomatic way to handle this in Flow. Opaque
types are simlar, but those only work within a single file. AFAIK,
there's no way to use a package as the boundary for opaqueness.
The immediate problem this presents is that the reconciler refactor will
involve changes to our internal data structures. I don't want to have to
fork every single package that happens to pass through a Fiber or
FiberRoot, or access any one of its fields. So my current plan is to
share the same Flow type across both forks. The shared type will be a
superset of each implementation's type, e.g. Fiber will have both an
`expirationTime` field and a `lanes` field. The implementations will
diverge, but not the types.
To do this, I lifted the type definitions into a separate module.
* Enable prefer-const rule
Stylistically I don't like this but Closure Compiler takes advantage of
this information.
* Auto-fix lints
* Manually fix the remaining callsites
* Rename lower case isomorphic default exports modules to upper case named exports
We're somewhat inconsistent here between e.g. ReactLazy and memo.
Let's pick one.
This also moves the responder, fundamental, scope creators from shared
since they're isomorphic and same as the other creators.
* Move some files that are specific to the react-reconciler from shared
Individual renderers are allowed to deep require into the reconciler.
* Move files specific to react-dom from shared
react-interactions is right now dom specific (it wasn't before) so we can
type check it together with other dom stuff. Avoids the need for
a shared ReactDOMTypes to be checked by RN for example.
* Move ReactWorkTags to the reconciler
* Move createPortal to export from reconciler
Otherwise Noop can't access it since it's not allowed deep requires.
* Replace all warning/lowPriWarning with console calls
* Replace console.warn/error with a custom wrapper at build time
* Fail the build for console.error/warn() where we can't read the stack
* prep for codemod
* prep warnings
* rename lint rules
* codemod for ifs
* shim www functions
* Handle more cases in the transform
* Thanks De Morgan
* Run the codemod
* Delete the transform
* Fix up confusing conditions manually
* Fix up www shims to match expected API
* Also check for low-pri warning in the lint rule
* Add Event Replaying Infra
* Wire up Roots and Suspense boundaries, to retry events, after they commit
* Replay discrete events in order in a separate scheduler callback
* Add continuous events
These events only replay their last target if the target is not yet
hydrated. That way we don't have to wait for a previously hovered
boundary before invoking the current target.
* Enable tests from before
These tests were written with replaying in mind and now we can properly
enable them.
* Unify replaying and dispatching
* Mark system flags as a replay and pass to legacy events
That way we can check if this is a replay and therefore needs a special
case. One such special case is "mouseover" where we check the
relatedTarget.
* Eagerly listen to all replayable events
To minimize breakages in a minor, I only do this for the new root APIs
since replaying only matters there anyway. Only if hydrating.
For Flare, I have to attach all active listeners since the current
system has one DOM listener for each. In a follow up I plan on optimizing
that by only attaching one if there's at least one active listener
which would allow us to start with only passive and then upgrade.
* Desperate attempt to save bytese
* Add test for mouseover replaying
We need to check if the "relatedTarget" is mounted due to how the old
event system dispatches from the "out" event.
* Fix for nested boundaries and suspense in root container
This is a follow up to #16673 which didn't have a test because it wasn't
observable yet. This shows that it had a bug.
* Rename RESPONDER_EVENT_SYSTEM to PLUGIN_EVENT_SYSTEM
* Don't invoke listeners on parent of dehydrated event target
* Move Suspense boundary check to getClosestInstanceFromNode
Now getClosestInstanceFromNode can return either a host component,
host text component or suspense component when the suspense
component is dehydrated.
We then use that to ignore events on a suspense component.
* Attach the HostRoot fiber to the DOM container
This lets us detect if an event happens on this root's subtree before it
has rendered something.
* Add todo
The approach of checking isFiberMounted answers if we might be in an
in-progress hydration but it doesn't answer which root or boundary
might be in-progress so we don't know what to wait for.
This needs some refactoring.
* Refactor isFiberMountedImpl to getNearestMountedFiber
We'll need the nearest boundary for event replaying so this prepares for
that.
This surfaced an issue that we attach Hydrating tag on the root but normally
this (and Placement) is attached on the child. This surfaced an issue
that this can lead to both Placement and Hydrating effects which is not
supported so we need to ensure that we only ever use one or the other.
* Add todo for bug I spotted
* Cache tags
* Check the ContainerInstanceKey before the InstanceKey
The container is inside the instance, so we must find it before the
instance, since otherwise we'll miss it.
* Refactor a bit to use less property access
* Add test for invoking an event before mount
* Add Hydration effect tag
This is equivalent to a "Placement" effect in that it's a new insertion
to the tree but it doesn't need an actual mutation.
It is only used to determine if a subtree has actually mounted yet.
* Use the Hydration flag for Roots
Previous roots had a Placement flag on them as a hack for this case but
since we have a special flag for it now, we can just use that.
* Add Flare test
This doesn't rely on checking the tag. When the alternate of a parent
is missing, it assumes it's a fragment indirection and moves onto the
next parent fiber.
Whenever we do this, Rollup needs to materialize this as an object.
This causes it to also add the Babel compatibility property which is
unnecessary bloat. However, since when we use these, we leak the object
this often also deopts any compiler optimizations.
If we really need an object we should export default an object.
Currently there is an exception for DOMTopLevelEventTypes since
listing out the imports is a PITA and it doesn't escape so it should
get properly inlined. We should probably move to a different pattern
to avoid this for consistency though.
* Simplify imports in ReactChildFiber
* Import type first in ReactCurrentFiber
* Simplify imports in ReactFiberBeginWork
* Simplify imports in ReactFiberScheduler
* Simplify import in ReactFiberTreeReflection
* Simplify import in ReactFiberUnwindWork
* Remove repeated import
* Fix imports from ReactFiberExpirationTime
* Master imports in ReactFiberBeginWork
* Introduce elementType field
This will be used to store the wrapped type of an element. E.g. pure and
lazy.
The existing type field will be used for the unwrapped type within them.
* Store the unwrapped type on the type field of lazy components
* Use the raw tags for lazy components
Instead, we check if the elementType and type are equal to test if
we need to resolve props. This is slightly slower in the normal case
but will yield less code and branching.
* Clean up lazy branches
* Collapse work tag numbering
* Split IndeterminateComponent out from Lazy
This way we don't have to check the type in a hacky way in the
indeterminate path. Also, lets us deal with lazy that resolves to
indeterminate and such.
* Missing clean up in rebase