Skip to content

RFC: DOM traversal and layout APIs in React Native#607

Merged
rubennorte merged 6 commits intoreact-native-community:mainfrom
rubennorte:dom-traversal-and-layout-apis
Sep 7, 2023
Merged

RFC: DOM traversal and layout APIs in React Native#607
rubennorte merged 6 commits intoreact-native-community:mainfrom
rubennorte:dom-traversal-and-layout-apis

Conversation

@rubennorte
Copy link
Copy Markdown
Contributor

@rubennorte rubennorte commented Mar 1, 2023

This is a proposal to allow users to access a representation of the native view hierarchy in React Native using DOM-compatible APIs.

A rendered version of the proposal can be read here

@tido64
Copy link
Copy Markdown

tido64 commented Mar 2, 2023

Hi, just some generic questions about this for my own understanding:

  • Is this implemented in the JS layer only? Do we need to make any changes on the native side in core?
  • What's the overhead of this API? Would it add to the final bundle size if unused?

@rubennorte
Copy link
Copy Markdown
Contributor Author

Hi, just some generic questions about this for my own understanding:

  • Is this implemented in the JS layer only? Do we need to make any changes on the native side in core?

@tido64 this also requires some new methods in the UIManager binding to expose the information to JavaScript. Something similar to these methods:

https://github.com/facebook/react-native/blob/851c8c671adcb563c9237e2080d5346413af1ac8/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp#L645-L677

We might also have to the a few methods in UIManager (like this one). In any case, most of these are to access information in the shadow tree.

  • What's the overhead of this API? Would it add to the final bundle size if unused?

We expect this to be low and can optimize as needed. The implementation wouldn't be as large as it looks.

With some other APIs defined as globals we can optimize them by removing the global altogether if not used. With these methods it's going to be harder as they're exposed through refs. It's unlikely we'll be able to statically determine whether they're used or not.

sammy-SC pushed a commit to facebook/react that referenced this pull request Mar 2, 2023
…derer (#26282)

## Summary

I'm going to start implementing parts of this proposal
react-native-community/discussions-and-proposals#607

As part of that implementation I'm going to refactor a few parts of the
interface between React and React Native. One of the main problems we
have right now is that we have private parts used by React and React
Native in the public instance exported by refs. I want to properly
separate that.

I saw that a few methods to attach event handlers imperatively on refs
were also exposing some things in the public instance (the
`_eventListeners`). I checked and these methods are unused, so we can
just clean them up instead of having to refactor them too. Adding
support for imperative event listeners is in the roadmap after this
proposal, and its implementation might differ after this refactor.

This is essentially a manual revert of #23386.

I'll submit more PRs after this for the rest of the refactor.

## How did you test this change?

Existing jest tests. Will test a React sync internally at Meta.
github-actions Bot pushed a commit to facebook/react that referenced this pull request Mar 2, 2023
…derer (#26282)

## Summary

I'm going to start implementing parts of this proposal
react-native-community/discussions-and-proposals#607

As part of that implementation I'm going to refactor a few parts of the
interface between React and React Native. One of the main problems we
have right now is that we have private parts used by React and React
Native in the public instance exported by refs. I want to properly
separate that.

I saw that a few methods to attach event handlers imperatively on refs
were also exposing some things in the public instance (the
`_eventListeners`). I checked and these methods are unused, so we can
just clean them up instead of having to refactor them too. Adding
support for imperative event listeners is in the roadmap after this
proposal, and its implementation might differ after this refactor.

This is essentially a manual revert of #23386.

I'll submit more PRs after this for the rest of the refactor.

## How did you test this change?

Existing jest tests. Will test a React sync internally at Meta.

DiffTrain build for [d49e0e0](d49e0e0)
@javache javache self-requested a review March 2, 2023 16:58
@rubennorte rubennorte force-pushed the dom-traversal-and-layout-apis branch from 38a7222 to ae807a7 Compare March 10, 2023 11:20
sammy-SC pushed a commit to facebook/react that referenced this pull request Mar 13, 2023
…ule in Fabric (#26321)

## Summary

The current definition of `Instance` in Fabric has 2 fields:
- `node`: reference to the native node in the shadow tree.
- `canonical`: public instance provided to users via refs + some
internal fields needed by Fabric.

We're currently using `canonical` not only as the public instance, but
also to store internal properties that Fabric needs to access in
different parts of the codebase. Those properties are, in fact,
available through refs as well, which breaks encapsulation.

This PR splits that into 2 separate fields, leaving the definition of
instance as:
- `node`: reference to the native node in the shadow tree.
- `publicInstance`: public instance provided to users via refs.
- Rest of internal fields needed by Fabric at the instance level.

This also migrates all the current usages of `canonical` to use the
right property depending on the use case.

To improve encapsulation (and in preparation for the implementation of
this [proposal to bring some DOM APIs to public instances in React
Native](react-native-community/discussions-and-proposals#607)),
this also **moves the creation of and the access to the public instance
to separate modules** (`ReactFabricPublicInstance` and
`ReactFabricPublicInstanceUtils`). In a following diff, that module will
be moved into the `react-native` repository and we'll access it through
`ReactNativePrivateInterface`.

## How did you test this change?

Existing unit tests.
Manually synced the PR in Meta infra and tested in Catalyst + the
integration with DevTools. Everything is working normally.
@rubennorte rubennorte requested a review from kelset March 13, 2023 22:59
facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Mar 14, 2023
Summary:
This adds a feature flag to enable all the new DOM traversal and layout APIs (in react-native-community/discussions-and-proposals#607).

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D43981608

fbshipit-source-id: 77bb1ee4faaaf30cfc8bb2e493763b168702f498
facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Mar 20, 2023
Summary:
This implements a basic version of HTMLCollection that's close to the spec but diverges in some things (e.g.: methods could be called with an instance created through `Object.create`, etc.).

This will be used soon to implement `ReadOnlyElement.children` (behind a flag).

See: react-native-community/discussions-and-proposals#607

Changelog: [internal]

Reviewed By: yungsters

Differential Revision: D44055912

fbshipit-source-id: 37bcd7c12916b95a258e6b2e5717a642f478abdf
facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Mar 20, 2023
Summary:
This implements a basic version of NodeList that's close to the spec but diverges in some things (e.g.: methods could be called with an instance created through `Object.create`, etc.).

This will be used soon to implement `ReadOnlyNode.childNodes` (behind a flag).

See: react-native-community/discussions-and-proposals#607

Changelog: [internal]

Reviewed By: yungsters

Differential Revision: D44055911

fbshipit-source-id: 10b435b06ea6f75eaead85f01c2703e05bb3bd37
facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Mar 20, 2023
Summary:
This implements a basic version of DOMRectList that's close to the spec but diverges in some things (e.g.: methods could be called with an instance created through `Object.create`, etc.).

This will be used soon to implement `ReadOnlyelement.getClientRects()` (behind a flag).

See: react-native-community/discussions-and-proposals#607

Changelog: [internal]

Reviewed By: yungsters

Differential Revision: D44060540

fbshipit-source-id: ad29b5c41f2778864e7dd7ece9223dcf73cd5d6c
facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Mar 20, 2023
Summary:
This just creates the class structure for `ReadOnlyNode`, `ReadOnlyElement` and `ReactNativeElement`, with all methods throwing as unimplemented.

These classes will be gated behind a feature flag, so merging incomplete work is ok.

This doesn't add the future setters that will log warnings / throw errors when used.

See: react-native-community/discussions-and-proposals#607
Changelog: [internal]

Reviewed By: rickhanlonii, yungsters

Differential Revision: D44060539

fbshipit-source-id: e489532fd365d9aa2bb8308847a35eb715d675e7
sammy-SC pushed a commit to facebook/react that referenced this pull request Mar 20, 2023
…26416)

## Summary

We are going to move the definition of public instances from React to
React Native to have them together with the native methods in Fabric
that they invoke. This will allow us to have a better type safety
between them and iterate faster on the implementation of this proposal:
react-native-community/discussions-and-proposals#607

The interface between React and React Native would look like this after
this change and a following PR (#26418):

React → React Native:
```javascript
ReactNativePrivateInterface.createPublicInstance // to provide via refs
ReactNativePrivateInterface.getNodeFromPublicInstance // for DevTools, commands, etc.
ReactNativePrivateInterface.getNativeTagFromPublicInstance // to implement `findNodeHandle`
```

React Native → React (ReactFabric):
```javascript
ReactFabric.getNodeFromInternalInstanceHandle // to get most recent node to call into native
ReactFabric.getPublicInstanceFromInternalInstanceHandle // to get public instances from results from native
```

## How did you test this change?

Flow
Existing unit tests
rubennorte added a commit to rubennorte/react-native that referenced this pull request Jun 12, 2023
Summary:
Pull Request resolved: facebook#37754

This adds a new method in Fabric to get the scroll position for an element, and uses it to implement the following methods as defined in  as defined in react-native-community/discussions-and-proposals#607 :
* `scrollTop`: indicates the number of pixels (in device independent pixels) from the content that have moved in the vertical axis in the scroll container.
* `scrollLeft`: indicates the number of pixels (in device independent pixels) from the content that have moved in the horizontal axis in the scroll container.

These API can provide decimal values.

Changelog: [internal]

Reviewed By: javache

Differential Revision: D44757811

fbshipit-source-id: 494fd45d149f28a7240fdc59e8997bd576a85773
facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Jun 12, 2023
Summary:
Pull Request resolved: #37754

This adds a new method in Fabric to get the scroll position for an element, and uses it to implement the following methods as defined in  as defined in react-native-community/discussions-and-proposals#607 :
* `scrollTop`: indicates the number of pixels (in device independent pixels) from the content that have moved in the vertical axis in the scroll container.
* `scrollLeft`: indicates the number of pixels (in device independent pixels) from the content that have moved in the horizontal axis in the scroll container.

These API can provide decimal values.

Changelog: [internal]

Reviewed By: javache

Differential Revision: D44757811

fbshipit-source-id: e1b58db8d9f61e823b62d54620a9a0deaae1566b
@rubennorte rubennorte force-pushed the dom-traversal-and-layout-apis branch from ae807a7 to 2f28942 Compare September 4, 2023 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants