diff --git a/.buckconfig b/.buckconfig index 3f1b5c6d11f092..272ffbbe1221a5 100644 --- a/.buckconfig +++ b/.buckconfig @@ -15,6 +15,3 @@ [alias] rntester = //packages/rn-tester/android/app:app - -[buildfile] - includes = //tools/build_defs/oss/preload.bzl diff --git a/.circleci/README.md b/.circleci/README.md index 9c944ef6d105c0..0ae32f93c4d13c 100644 --- a/.circleci/README.md +++ b/.circleci/README.md @@ -1,5 +1,172 @@ # Circle CI -This directory is home to the Circle CI configuration file. Circle is our continuous integration service provider. You can see the overall status of React Native's builds at https://circleci.com/gh/facebook/react-native +This directory is home to the Circle CI configuration files. Circle is our continuous integration service provider. You can see the overall status of React Native's builds at https://circleci.com/gh/facebook/react-native You may also see an individual PR's build status by scrolling down to the Checks section in the PR. + +## Purposes + +We use CircleCI for mainly 3 purposes: + +1. Testing changes +2. Release Nightlies +3. Release Stable Versions of React Native + +When testing changes, we run all the tests on commits that lands on `main`. For commits in PR, we try to understand which kind of changes the PR is about and we try to selectively run only the relevant tests. so, for example, if a PR only touches iOS files, we are going to run only iOS tests. + +A Nighly job runs every day at around 9:00 PM, GMT. They run from `main` and they publish a version of React Native using the current state of the codebase, creating a version number that follows the format: `0..0-nightly--`. +The nightly job also publish all the monorepo packages, taking care of updating the transitive dependencies of those packages. + +Stable versions are released manually by the Release Crew and they run from a stable branch. Stable branches have the shape of `0.-stable`. + +## How It Works? + +CircleCI execution is now split in two steps: +- Setup +- Testing + +The setup step takes care of analyzing the changes in the PR and of deciding which jobs needs to run. + +The testing flow is a set of workflows that executes the required tests. + +### Setup + +The code of the setup workflow lives in the root [`config.yml`](https://github.com/facebook/react-native/blob/main/.circleci/config.yml) file. +It uses the `Continuation orb` from CircleCI to start a CI flow that depends on the changes present in the PR. + +If the changes are not coming from a PR (either a simple commit or if the CI is running on main) **we always run all the tests** as a cautionary measure. + +The setup job has also to expose all the pipeline parameters that we would need to pass to the actual workflow. Those parameters are **automatically forwarded** to the workflows that are started as a result of the setup. + +The setup job uses a JS script to carry on its logic. The [`pipeline_selection.js`](https://github.com/facebook/react-native/blob/main/scripts/circleci/pipeline_selection.js) script can be invoked with two commands: +- `filter-jobs` +- `create-configs` + +The **`filter-jobs`** command takes care of creating a JSON representation of the tests we need to run based on the changes in the PR. + +The **`create-configs`** command consumes the JSON representation to create a CircleCI configuration that can then executes all the required tests. + +#### Creating a Configuration + +To create a configuration, the `pipeline-selection` scripts collates together various pieces of `YML` files that lives in the [`Configurations` folder](https://github.com/facebook/react-native/tree/main/.circleci/configurations). + +The order in which these files are appended is **important** and it always contains the following.: + +1. `top_level.yml`: this file contains some high level directives for CircleCI, like the version, the list of orbs, the cache-keys, and the pipeline parameters that can be used by the workflows. +2. `executors.yml`: this file contains the list of the executors used in our jobs and their configurations. +3. `commands.yml`: this file contains all the commands that can be used by jobs to executes. Commands are reusable functions that are shared by multiple jobs. +4. `jobs.yml`: this file contains the jobs that are used by workflows to carry on some specific tasks. They are composed of sequential commands. +5. `workflows.yml`: this file contains the shared workflows that needs to (or can) be always executed, no matter which kind of changes are pushed to CI. An example of these workflows is `analysis` (which is always executed) or `nightly` (which can be executed if a specific pipeline parameter is passed to the CI). + +Then, the `pipeline_selection create-configs` attach some specific test workflows, depending on the changes that are present in the PR. These change-dependent workflows live in the [`test_workflows`](https://github.com/facebook/react-native/tree/main/.circleci/configurations/test_workflows) folder. +These workflows are: +* `testAll.yml` => runs all the possible tests. This workflow is executed on main and on PRs which change set touches both iOS and Android +* `testAndroid.yml` => runs all the build steps and Android tests. This is used on changes that happens on the Android codebase and infra (`ReactAndroid` folder) +* `testIOS.yml` => runs all the build steps and iOS tests. This is used on changes that happens on the iOS codebase and infra (`React` folder) +* `testE2E.yml` => runs the E2E tests. As of today, E2E tests can be triggered if the commit message contains the `#run-e2e-tests` tag. +* `testJS.yml` => For all the changes that do not touch native/platform code, we only run JS tests. + +Notice that if there are changes on files that do not represents code (for example `.md` files like this one or the `Changelog`) we don't run any CI. + +## Test workflows + +The test workflows for native code are composed of 2 parts: +- building React Native +- testing + +Building React Native requires us to build several parts of it: +1. We need to build the Hermes JS engine +2. We need to build Android to create prebuilds +3. We need to package everything in an npm package that will mimic a React native release +4. We need to create a local maven repository + +### Building Hermes Engine + +#### Android +The `build_android` workflows takes care of building the Android version of Hermes and to put it properly in a local maven repository. +See the [Build Android](#build_android) section below. + +#### iOS +Hermes is a very complicated item to build for iOS. +It is composed of the Hermes compiler (HermesC) and of the actual engine. + +Hermes is shipped as a universal XCFramework. This means that we need to build all the architecture slices and then put them together in the XCFramework archive. +We also need to build 2 configurations: Debug and Release. + +In order to be efficient and to save costs, we parallelize the process as much as possible: + +1. We prepare the environment for building Hermes. +2. We build HermesC which is required by all the slices. +3. We start 8 jobs to build all the required slices in parallel: + 1. `iphone` slice, Debug mode + 1. `iphonesimulator` slice, Debug mode + 1. `macos` slice, Debug mode + 1. `catalyst` slice, Debug mode + 1. `iphone` slice, Release mode + 1. `iphonesimulator` slice, Release mode + 1. `macos` slice, Release mode + 1. `catalyst` slice, Release mode +4. We then have 2 jobs to create the Debug and Release tarballs in parallel. + 1. The Debug job receives the 4 Debug slices + 1. The Release job receives the 4 Release slices + +The `Debug` and `Release` tarball are then uploaded as artifacts. Notice that these we use these artifacts to **test the release** of React Native. + +While building Hermes, we take also care of building the dSYMs. A dSYM (Debug Symbols) is an archive that contains the Debug Symbols that users can load to de-symbolicate the Hermes Stack traces. These symbols are published when we create a React Native release. + +A lot of these build steps are automated by some shell scripts that lives in the [`react-native/packages/react-native/sdks/hermes-engine/utils` folder](https://github.com/facebook/react-native/tree/main/packages/react-native/sdks/hermes-engine/utils). + +### Build Android + +The android build is all managed by Gradle, so building android should be as easy as calling a [`gradle` command](https://github.com/facebook/react-native/blob/main/.circleci/configurations/jobs.yml#L268-L274). + +The relevant part here is that the build android generates a `maven-local` repository that is passed to the [`build_npm_package`](https://github.com/facebook/react-native/blob/main/.circleci/configurations/jobs.yml#L1182) and that we use to test the releases. + +### Build NPM package + +This job is the responsible to create an NPM package that is suitable to be released or tested in CI. +If we are in a release flow (for example the Nightly workflow), it also proceed with the publication. + +The job can be invoked with different parameters: +- `dry-run` => it does not publish anything, but prepare the artifacts to be used for testing +- `nightly` => it creates the artifacts and publish a nightly version of React Native. +- `release` => it creates the artifacts and publish a stable version of React Native. + +The build NPM package takes all the artifacts produced in the previous steps (iOS' Hermes, iOS' Hermes dSYMs, Android's `maven-local`) and creates an npm package packing all the code. + +If in a release mode, it also proceed publishing the NPM package to NPM, and the artifacts to Maven central, which we use to distribute all the artifacts. + +This job also uploads the `maven-local` repository and a zipped version of the npm package to CircleCI's artifacts. We use these artifacts to **test the release** of React Native. + +## Testing React Native +React Native tests runs in two different scenarios: +- RNTester +- A New App + +### RNTester +RNTester is our internal testing app. It is a fully working React Native app that lives in the [`react-native/packages/rn-tester` folder](https://github.com/facebook/react-native/tree/main/packages/rn-tester) of the repository. +RNTester is an app which contains code that exercise most part of the React Native frameworks. +It also has the feature of building React Native **from source**. For that reason, it does not have to wait for the NPM package to be ready, but RNTester's tests can start as soon as the `build_android` step and the step that builds Hermes for iOS are done. + +Notice the Tests on RNTester for iOS consumes the Hermes engine that is built in the previous steps. + +For Android, these tests creates an APK that is uploaded as an artifact in CircleCI. We use these artifacts to **test the releases** of React Native.. + +### A New App +The React Native repo contains a template app in the [`react-native/packages/react-native/template` folder]() that is used to spin up a new application that is preconfigured with React Native. + +We have several tests that we run starting from the template, testing various configurations: +- Debug/Release +- JSC/Hermes (two different JS engine we support) +- New/Old Architecture (two different Architectures for React Native) + +We want to test all the React Native changes against the template, but we can't publish a React native version on each change that is merged. Therefore, to run tests on the template we use a NPM registry proxy called [Verdaccio](https://verdaccio.org/). + +When running a Template test our CI follows roughly these steps: +1. Prepare the executor +2. Start a Verdaccio server +3. Publish on Verdaccio all the monorepo [packages](https://github.com/facebook/react-native/tree/main/packages) on which React Native depends on. +4. Publish on Verdaccio the react-native NPM package that has been created in the NPM step +5. Spin up a new React native apps from the template, downloading react-native from Verdaccio. + +In this way, we are sure that we can test all the changes that happen in React Native on a new React Native app. diff --git a/.circleci/config.yml b/.circleci/config.yml index 8430e0e37ec756..94fed2af278951 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -60,7 +60,7 @@ jobs: value: << pipeline.git.branch >> steps: - run: - name: "[Main or Stable] Create input fo config to test everything" + name: "[Main or Stable] Create input for config to test everything" command: | mkdir -p /tmp/circleci/ echo '{ "run_all": true }' > /tmp/circleci/pipeline_config.json diff --git a/.circleci/configurations/test_workflows/testAll.yml b/.circleci/configurations/test_workflows/testAll.yml index fe497a7922a973..7afd7d2171f57d 100644 --- a/.circleci/configurations/test_workflows/testAll.yml +++ b/.circleci/configurations/test_workflows/testAll.yml @@ -62,18 +62,17 @@ flavor: "Debug" executor: reactnativeios-lts - test_ios_template: + architecture: "OldArch" requires: - build_npm_package matrix: parameters: - architecture: ["NewArch", "OldArch"] flavor: ["Debug", "Release"] jsengine: ["Hermes", "JSC"] use_frameworks: ["StaticLibraries", "DynamicFrameworks"] exclude: # This config is tested with Ruby 3.2.0. Let's not double test it. - - architecture: "NewArch" - flavor: "Debug" + - flavor: "Debug" jsengine: "Hermes" use_frameworks: "StaticLibraries" - test_ios_rntester: @@ -84,33 +83,30 @@ architecture: "NewArch" executor: reactnativeios-lts - test_ios_rntester: + architecture: "NewArch" requires: - build_hermes_macos matrix: parameters: - architecture: ["NewArch", "OldArch"] jsengine: ["Hermes", "JSC"] use_frameworks: ["StaticLibraries", "DynamicFrameworks"] exclude: # Tested by test_ios-Hermes - - architecture: "OldArch" - jsengine: "Hermes" + - jsengine: "Hermes" use_frameworks: "StaticLibraries" # Tested by test_ios-JSC - - architecture: "OldArch" - jsengine: "JSC" + - jsengine: "JSC" use_frameworks: "StaticLibraries" # Tested with Ruby 3.2.0, do not test this twice. - - architecture: "NewArch" - jsengine: "Hermes" + - jsengine: "Hermes" use_frameworks: "StaticLibraries" - test_ios_rntester: run_unit_tests: true - architecture: "OldArch" use_frameworks: "StaticLibraries" ruby_version: "2.6.10" requires: - build_hermes_macos matrix: parameters: + architecture: ["OldArch", "NewArch"] jsengine: ["Hermes", "JSC"] diff --git a/.circleci/configurations/test_workflows/testIOS.yml b/.circleci/configurations/test_workflows/testIOS.yml index bff9e73786d795..eb6cf50a527aa3 100644 --- a/.circleci/configurations/test_workflows/testIOS.yml +++ b/.circleci/configurations/test_workflows/testIOS.yml @@ -53,18 +53,17 @@ flavor: "Debug" executor: reactnativeios-lts - test_ios_template: + architecture: "OldArch" requires: - build_npm_package matrix: parameters: - architecture: ["NewArch", "OldArch"] flavor: ["Debug", "Release"] jsengine: ["Hermes", "JSC"] use_frameworks: ["StaticLibraries", "DynamicFrameworks"] exclude: # Tested with Ruby 3.2.0, let's not double test this - - architecture: "NewArch" - flavor: "Debug" + - flavor: "Debug" jsengine: "Hermes" use_frameworks: "StaticLibraries" - test_ios_rntester: @@ -75,33 +74,30 @@ architecture: "NewArch" executor: reactnativeios-lts - test_ios_rntester: + architecture: "NewArch" requires: - build_hermes_macos matrix: parameters: - architecture: ["NewArch", "OldArch"] jsengine: ["Hermes", "JSC"] use_frameworks: ["StaticLibraries", "DynamicFrameworks"] exclude: # Tested by test_ios-Hermes - - architecture: "OldArch" - jsengine: "Hermes" + - jsengine: "Hermes" use_frameworks: "StaticLibraries" # Tested by test_ios-JSC - - architecture: "OldArch" - jsengine: "JSC" + - jsengine: "JSC" use_frameworks: "StaticLibraries" # Tested with Ruby 3.2.0, let's not double test this - - architecture: "NewArch" - jsengine: "Hermes" + - jsengine: "Hermes" use_frameworks: "StaticLibraries" - test_ios_rntester: run_unit_tests: true - architecture: "OldArch" use_frameworks: "StaticLibraries" ruby_version: "2.6.10" requires: - build_hermes_macos matrix: parameters: + architecture: ["NewArch", "OldArch"] jsengine: ["Hermes", "JSC"] diff --git a/.flowconfig b/.flowconfig index b50e7305d63be3..e50161b27b6e65 100644 --- a/.flowconfig +++ b/.flowconfig @@ -82,4 +82,4 @@ untyped-import untyped-type-import [version] -^0.222.0 +^0.223.0 diff --git a/flow-typed/npm/babel-traverse_v7.x.x.js b/flow-typed/npm/babel-traverse_v7.x.x.js index 2e3520dd23b98a..b35fd7863068c5 100644 --- a/flow-typed/npm/babel-traverse_v7.x.x.js +++ b/flow-typed/npm/babel-traverse_v7.x.x.js @@ -293,9 +293,6 @@ declare module '@babel/traverse' { dereference(): void; } - declare function getNodePathType(node: BabelNode): NodePath<>; - declare function getNodePathType(nodes: Array): Array>; - declare type Opts = {...}; declare export class NodePath<+TNode: BabelNode = BabelNode> { @@ -733,7 +730,7 @@ declare module '@babel/traverse' { get>( key: TKey, context?: boolean | TraversalContext, - ): $Call; + ): TNode[TKey] extends BabelNode ? NodePath<> : Array>; get( key: string, diff --git a/flow-typed/npm/babel-types_v7.x.x.js b/flow-typed/npm/babel-types_v7.x.x.js index 74249fe3c2fd76..6f344941bc71fd 100644 --- a/flow-typed/npm/babel-types_v7.x.x.js +++ b/flow-typed/npm/babel-types_v7.x.x.js @@ -3443,308 +3443,308 @@ declare module "@babel/types" { declare export function tsTypeParameterInstantiation(params: Array): BabelNodeTSTypeParameterInstantiation; declare export function tsTypeParameterDeclaration(params: Array): BabelNodeTSTypeParameterDeclaration; declare export function tsTypeParameter(constraint?: BabelNodeTSType, _default?: BabelNodeTSType, name: string): BabelNodeTSTypeParameter; - declare export function isArrayExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ArrayExpression'); - declare export function isAssignmentExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'AssignmentExpression'); - declare export function isBinaryExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'BinaryExpression'); - declare export function isInterpreterDirective(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'InterpreterDirective'); - declare export function isDirective(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'Directive'); - declare export function isDirectiveLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DirectiveLiteral'); - declare export function isBlockStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'BlockStatement'); - declare export function isBreakStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'BreakStatement'); - declare export function isCallExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'CallExpression'); - declare export function isCatchClause(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'CatchClause'); - declare export function isConditionalExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ConditionalExpression'); - declare export function isContinueStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ContinueStatement'); - declare export function isDebuggerStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DebuggerStatement'); - declare export function isDoWhileStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DoWhileStatement'); - declare export function isEmptyStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EmptyStatement'); - declare export function isExpressionStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ExpressionStatement'); - declare export function isFile(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'File'); - declare export function isForInStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ForInStatement'); - declare export function isForStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ForStatement'); - declare export function isFunctionDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'FunctionDeclaration'); - declare export function isFunctionExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'FunctionExpression'); - declare export function isIdentifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'Identifier'); - declare export function isIfStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'IfStatement'); - declare export function isLabeledStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'LabeledStatement'); - declare export function isStringLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'StringLiteral'); - declare export function isNumericLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'NumericLiteral'); - declare export function isNullLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'NullLiteral'); - declare export function isBooleanLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'BooleanLiteral'); - declare export function isRegExpLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'RegExpLiteral'); - declare export function isLogicalExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'LogicalExpression'); - declare export function isMemberExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'MemberExpression'); - declare export function isNewExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'NewExpression'); - declare export function isProgram(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'Program'); - declare export function isObjectExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ObjectExpression'); - declare export function isObjectMethod(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ObjectMethod'); - declare export function isObjectProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ObjectProperty'); - declare export function isRestElement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'RestElement'); - declare export function isReturnStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ReturnStatement'); - declare export function isSequenceExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'SequenceExpression'); - declare export function isParenthesizedExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ParenthesizedExpression'); - declare export function isSwitchCase(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'SwitchCase'); - declare export function isSwitchStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'SwitchStatement'); - declare export function isThisExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ThisExpression'); - declare export function isThrowStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ThrowStatement'); - declare export function isTryStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TryStatement'); - declare export function isUnaryExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'UnaryExpression'); - declare export function isUpdateExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'UpdateExpression'); - declare export function isVariableDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'VariableDeclaration'); - declare export function isVariableDeclarator(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'VariableDeclarator'); - declare export function isWhileStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'WhileStatement'); - declare export function isWithStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'WithStatement'); - declare export function isAssignmentPattern(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'AssignmentPattern'); - declare export function isArrayPattern(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ArrayPattern'); - declare export function isArrowFunctionExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ArrowFunctionExpression'); - declare export function isClassBody(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ClassBody'); - declare export function isClassExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ClassExpression'); - declare export function isClassDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ClassDeclaration'); - declare export function isExportAllDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ExportAllDeclaration'); - declare export function isExportDefaultDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ExportDefaultDeclaration'); - declare export function isExportNamedDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ExportNamedDeclaration'); - declare export function isExportSpecifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ExportSpecifier'); - declare export function isForOfStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ForOfStatement'); - declare export function isImportDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ImportDeclaration'); - declare export function isImportDefaultSpecifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ImportDefaultSpecifier'); - declare export function isImportNamespaceSpecifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ImportNamespaceSpecifier'); - declare export function isImportSpecifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ImportSpecifier'); - declare export function isMetaProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'MetaProperty'); - declare export function isClassMethod(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ClassMethod'); - declare export function isObjectPattern(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ObjectPattern'); - declare export function isSpreadElement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'SpreadElement'); - declare export function isSuper(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'Super'); - declare export function isTaggedTemplateExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TaggedTemplateExpression'); - declare export function isTemplateElement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TemplateElement'); - declare export function isTemplateLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TemplateLiteral'); - declare export function isYieldExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'YieldExpression'); - declare export function isAwaitExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'AwaitExpression'); - declare export function isImport(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'Import'); - declare export function isBigIntLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'BigIntLiteral'); - declare export function isExportNamespaceSpecifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ExportNamespaceSpecifier'); - declare export function isOptionalMemberExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'OptionalMemberExpression'); - declare export function isOptionalCallExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'OptionalCallExpression'); - declare export function isClassProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ClassProperty'); - declare export function isClassAccessorProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ClassAccessorProperty'); - declare export function isClassPrivateProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ClassPrivateProperty'); - declare export function isClassPrivateMethod(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ClassPrivateMethod'); - declare export function isPrivateName(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'PrivateName'); - declare export function isStaticBlock(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'StaticBlock'); - declare export function isAnyTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'AnyTypeAnnotation'); - declare export function isArrayTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ArrayTypeAnnotation'); - declare export function isBooleanTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'BooleanTypeAnnotation'); - declare export function isBooleanLiteralTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'BooleanLiteralTypeAnnotation'); - declare export function isNullLiteralTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'NullLiteralTypeAnnotation'); - declare export function isClassImplements(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ClassImplements'); - declare export function isDeclareClass(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclareClass'); - declare export function isDeclareFunction(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclareFunction'); - declare export function isDeclareInterface(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclareInterface'); - declare export function isDeclareModule(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclareModule'); - declare export function isDeclareModuleExports(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclareModuleExports'); - declare export function isDeclareTypeAlias(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclareTypeAlias'); - declare export function isDeclareOpaqueType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclareOpaqueType'); - declare export function isDeclareVariable(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclareVariable'); - declare export function isDeclareExportDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclareExportDeclaration'); - declare export function isDeclareExportAllDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclareExportAllDeclaration'); - declare export function isDeclaredPredicate(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DeclaredPredicate'); - declare export function isExistsTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ExistsTypeAnnotation'); - declare export function isFunctionTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'FunctionTypeAnnotation'); - declare export function isFunctionTypeParam(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'FunctionTypeParam'); - declare export function isGenericTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'GenericTypeAnnotation'); - declare export function isInferredPredicate(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'InferredPredicate'); - declare export function isInterfaceExtends(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'InterfaceExtends'); - declare export function isInterfaceDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'InterfaceDeclaration'); - declare export function isInterfaceTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'InterfaceTypeAnnotation'); - declare export function isIntersectionTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'IntersectionTypeAnnotation'); - declare export function isMixedTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'MixedTypeAnnotation'); - declare export function isEmptyTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EmptyTypeAnnotation'); - declare export function isNullableTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'NullableTypeAnnotation'); - declare export function isNumberLiteralTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'NumberLiteralTypeAnnotation'); - declare export function isNumberTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'NumberTypeAnnotation'); - declare export function isObjectTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ObjectTypeAnnotation'); - declare export function isObjectTypeInternalSlot(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ObjectTypeInternalSlot'); - declare export function isObjectTypeCallProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ObjectTypeCallProperty'); - declare export function isObjectTypeIndexer(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ObjectTypeIndexer'); - declare export function isObjectTypeProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ObjectTypeProperty'); - declare export function isObjectTypeSpreadProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ObjectTypeSpreadProperty'); - declare export function isOpaqueType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'OpaqueType'); - declare export function isQualifiedTypeIdentifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'QualifiedTypeIdentifier'); - declare export function isStringLiteralTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'StringLiteralTypeAnnotation'); - declare export function isStringTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'StringTypeAnnotation'); - declare export function isSymbolTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'SymbolTypeAnnotation'); - declare export function isThisTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ThisTypeAnnotation'); - declare export function isTupleTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TupleTypeAnnotation'); - declare export function isTypeofTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TypeofTypeAnnotation'); - declare export function isTypeAlias(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TypeAlias'); - declare export function isTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TypeAnnotation'); - declare export function isTypeCastExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TypeCastExpression'); - declare export function isTypeParameter(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TypeParameter'); - declare export function isTypeParameterDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TypeParameterDeclaration'); - declare export function isTypeParameterInstantiation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TypeParameterInstantiation'); - declare export function isUnionTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'UnionTypeAnnotation'); - declare export function isVariance(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'Variance'); - declare export function isVoidTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'VoidTypeAnnotation'); - declare export function isEnumDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EnumDeclaration'); - declare export function isEnumBooleanBody(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EnumBooleanBody'); - declare export function isEnumNumberBody(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EnumNumberBody'); - declare export function isEnumStringBody(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EnumStringBody'); - declare export function isEnumSymbolBody(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EnumSymbolBody'); - declare export function isEnumBooleanMember(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EnumBooleanMember'); - declare export function isEnumNumberMember(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EnumNumberMember'); - declare export function isEnumStringMember(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EnumStringMember'); - declare export function isEnumDefaultedMember(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'EnumDefaultedMember'); - declare export function isIndexedAccessType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'IndexedAccessType'); - declare export function isOptionalIndexedAccessType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'OptionalIndexedAccessType'); - declare export function isJSXAttribute(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXAttribute'); - declare export function isJSXClosingElement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXClosingElement'); - declare export function isJSXElement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXElement'); - declare export function isJSXEmptyExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXEmptyExpression'); - declare export function isJSXExpressionContainer(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXExpressionContainer'); - declare export function isJSXSpreadChild(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXSpreadChild'); - declare export function isJSXIdentifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXIdentifier'); - declare export function isJSXMemberExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXMemberExpression'); - declare export function isJSXNamespacedName(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXNamespacedName'); - declare export function isJSXOpeningElement(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXOpeningElement'); - declare export function isJSXSpreadAttribute(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXSpreadAttribute'); - declare export function isJSXText(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXText'); - declare export function isJSXFragment(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXFragment'); - declare export function isJSXOpeningFragment(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXOpeningFragment'); - declare export function isJSXClosingFragment(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'JSXClosingFragment'); - declare export function isNoop(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'Noop'); - declare export function isPlaceholder(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'Placeholder'); - declare export function isV8IntrinsicIdentifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'V8IntrinsicIdentifier'); - declare export function isArgumentPlaceholder(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ArgumentPlaceholder'); - declare export function isBindExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'BindExpression'); - declare export function isImportAttribute(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ImportAttribute'); - declare export function isDecorator(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'Decorator'); - declare export function isDoExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DoExpression'); - declare export function isExportDefaultSpecifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ExportDefaultSpecifier'); - declare export function isRecordExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'RecordExpression'); - declare export function isTupleExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TupleExpression'); - declare export function isDecimalLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'DecimalLiteral'); - declare export function isModuleExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'ModuleExpression'); - declare export function isTopicReference(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TopicReference'); - declare export function isPipelineTopicExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'PipelineTopicExpression'); - declare export function isPipelineBareFunction(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'PipelineBareFunction'); - declare export function isPipelinePrimaryTopicReference(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'PipelinePrimaryTopicReference'); - declare export function isTSParameterProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSParameterProperty'); - declare export function isTSDeclareFunction(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSDeclareFunction'); - declare export function isTSDeclareMethod(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSDeclareMethod'); - declare export function isTSQualifiedName(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSQualifiedName'); - declare export function isTSCallSignatureDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSCallSignatureDeclaration'); - declare export function isTSConstructSignatureDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSConstructSignatureDeclaration'); - declare export function isTSPropertySignature(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSPropertySignature'); - declare export function isTSMethodSignature(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSMethodSignature'); - declare export function isTSIndexSignature(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSIndexSignature'); - declare export function isTSAnyKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSAnyKeyword'); - declare export function isTSBooleanKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSBooleanKeyword'); - declare export function isTSBigIntKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSBigIntKeyword'); - declare export function isTSIntrinsicKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSIntrinsicKeyword'); - declare export function isTSNeverKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSNeverKeyword'); - declare export function isTSNullKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSNullKeyword'); - declare export function isTSNumberKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSNumberKeyword'); - declare export function isTSObjectKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSObjectKeyword'); - declare export function isTSStringKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSStringKeyword'); - declare export function isTSSymbolKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSSymbolKeyword'); - declare export function isTSUndefinedKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSUndefinedKeyword'); - declare export function isTSUnknownKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSUnknownKeyword'); - declare export function isTSVoidKeyword(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSVoidKeyword'); - declare export function isTSThisType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSThisType'); - declare export function isTSFunctionType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSFunctionType'); - declare export function isTSConstructorType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSConstructorType'); - declare export function isTSTypeReference(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypeReference'); - declare export function isTSTypePredicate(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypePredicate'); - declare export function isTSTypeQuery(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypeQuery'); - declare export function isTSTypeLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypeLiteral'); - declare export function isTSArrayType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSArrayType'); - declare export function isTSTupleType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTupleType'); - declare export function isTSOptionalType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSOptionalType'); - declare export function isTSRestType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSRestType'); - declare export function isTSNamedTupleMember(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSNamedTupleMember'); - declare export function isTSUnionType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSUnionType'); - declare export function isTSIntersectionType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSIntersectionType'); - declare export function isTSConditionalType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSConditionalType'); - declare export function isTSInferType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSInferType'); - declare export function isTSParenthesizedType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSParenthesizedType'); - declare export function isTSTypeOperator(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypeOperator'); - declare export function isTSIndexedAccessType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSIndexedAccessType'); - declare export function isTSMappedType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSMappedType'); - declare export function isTSLiteralType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSLiteralType'); - declare export function isTSExpressionWithTypeArguments(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSExpressionWithTypeArguments'); - declare export function isTSInterfaceDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSInterfaceDeclaration'); - declare export function isTSInterfaceBody(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSInterfaceBody'); - declare export function isTSTypeAliasDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypeAliasDeclaration'); - declare export function isTSInstantiationExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSInstantiationExpression'); - declare export function isTSAsExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSAsExpression'); - declare export function isTSSatisfiesExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSSatisfiesExpression'); - declare export function isTSTypeAssertion(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypeAssertion'); - declare export function isTSEnumDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSEnumDeclaration'); - declare export function isTSEnumMember(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSEnumMember'); - declare export function isTSModuleDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSModuleDeclaration'); - declare export function isTSModuleBlock(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSModuleBlock'); - declare export function isTSImportType(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSImportType'); - declare export function isTSImportEqualsDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSImportEqualsDeclaration'); - declare export function isTSExternalModuleReference(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSExternalModuleReference'); - declare export function isTSNonNullExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSNonNullExpression'); - declare export function isTSExportAssignment(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSExportAssignment'); - declare export function isTSNamespaceExportDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSNamespaceExportDeclaration'); - declare export function isTSTypeAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypeAnnotation'); - declare export function isTSTypeParameterInstantiation(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypeParameterInstantiation'); - declare export function isTSTypeParameterDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypeParameterDeclaration'); - declare export function isTSTypeParameter(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'TSTypeParameter'); - declare export function isStandardized(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ArrayExpression' || node.type === 'AssignmentExpression' || node.type === 'BinaryExpression' || node.type === 'InterpreterDirective' || node.type === 'Directive' || node.type === 'DirectiveLiteral' || node.type === 'BlockStatement' || node.type === 'BreakStatement' || node.type === 'CallExpression' || node.type === 'CatchClause' || node.type === 'ConditionalExpression' || node.type === 'ContinueStatement' || node.type === 'DebuggerStatement' || node.type === 'DoWhileStatement' || node.type === 'EmptyStatement' || node.type === 'ExpressionStatement' || node.type === 'File' || node.type === 'ForInStatement' || node.type === 'ForStatement' || node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'Identifier' || node.type === 'IfStatement' || node.type === 'LabeledStatement' || node.type === 'StringLiteral' || node.type === 'NumericLiteral' || node.type === 'NullLiteral' || node.type === 'BooleanLiteral' || node.type === 'RegExpLiteral' || node.type === 'LogicalExpression' || node.type === 'MemberExpression' || node.type === 'NewExpression' || node.type === 'Program' || node.type === 'ObjectExpression' || node.type === 'ObjectMethod' || node.type === 'ObjectProperty' || node.type === 'RestElement' || node.type === 'ReturnStatement' || node.type === 'SequenceExpression' || node.type === 'ParenthesizedExpression' || node.type === 'SwitchCase' || node.type === 'SwitchStatement' || node.type === 'ThisExpression' || node.type === 'ThrowStatement' || node.type === 'TryStatement' || node.type === 'UnaryExpression' || node.type === 'UpdateExpression' || node.type === 'VariableDeclaration' || node.type === 'VariableDeclarator' || node.type === 'WhileStatement' || node.type === 'WithStatement' || node.type === 'AssignmentPattern' || node.type === 'ArrayPattern' || node.type === 'ArrowFunctionExpression' || node.type === 'ClassBody' || node.type === 'ClassExpression' || node.type === 'ClassDeclaration' || node.type === 'ExportAllDeclaration' || node.type === 'ExportDefaultDeclaration' || node.type === 'ExportNamedDeclaration' || node.type === 'ExportSpecifier' || node.type === 'ForOfStatement' || node.type === 'ImportDeclaration' || node.type === 'ImportDefaultSpecifier' || node.type === 'ImportNamespaceSpecifier' || node.type === 'ImportSpecifier' || node.type === 'MetaProperty' || node.type === 'ClassMethod' || node.type === 'ObjectPattern' || node.type === 'SpreadElement' || node.type === 'Super' || node.type === 'TaggedTemplateExpression' || node.type === 'TemplateElement' || node.type === 'TemplateLiteral' || node.type === 'YieldExpression' || node.type === 'AwaitExpression' || node.type === 'Import' || node.type === 'BigIntLiteral' || node.type === 'ExportNamespaceSpecifier' || node.type === 'OptionalMemberExpression' || node.type === 'OptionalCallExpression' || node.type === 'ClassProperty' || node.type === 'ClassAccessorProperty' || node.type === 'ClassPrivateProperty' || node.type === 'ClassPrivateMethod' || node.type === 'PrivateName' || node.type === 'StaticBlock')); - declare export function isExpression(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ArrayExpression' || node.type === 'AssignmentExpression' || node.type === 'BinaryExpression' || node.type === 'CallExpression' || node.type === 'ConditionalExpression' || node.type === 'FunctionExpression' || node.type === 'Identifier' || node.type === 'StringLiteral' || node.type === 'NumericLiteral' || node.type === 'NullLiteral' || node.type === 'BooleanLiteral' || node.type === 'RegExpLiteral' || node.type === 'LogicalExpression' || node.type === 'MemberExpression' || node.type === 'NewExpression' || node.type === 'ObjectExpression' || node.type === 'SequenceExpression' || node.type === 'ParenthesizedExpression' || node.type === 'ThisExpression' || node.type === 'UnaryExpression' || node.type === 'UpdateExpression' || node.type === 'ArrowFunctionExpression' || node.type === 'ClassExpression' || node.type === 'MetaProperty' || node.type === 'Super' || node.type === 'TaggedTemplateExpression' || node.type === 'TemplateLiteral' || node.type === 'YieldExpression' || node.type === 'AwaitExpression' || node.type === 'Import' || node.type === 'BigIntLiteral' || node.type === 'OptionalMemberExpression' || node.type === 'OptionalCallExpression' || node.type === 'TypeCastExpression' || node.type === 'JSXElement' || node.type === 'JSXFragment' || node.type === 'BindExpression' || node.type === 'DoExpression' || node.type === 'RecordExpression' || node.type === 'TupleExpression' || node.type === 'DecimalLiteral' || node.type === 'ModuleExpression' || node.type === 'TopicReference' || node.type === 'PipelineTopicExpression' || node.type === 'PipelineBareFunction' || node.type === 'PipelinePrimaryTopicReference' || node.type === 'TSInstantiationExpression' || node.type === 'TSAsExpression' || node.type === 'TSSatisfiesExpression' || node.type === 'TSTypeAssertion' || node.type === 'TSNonNullExpression')); - declare export function isBinary(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'BinaryExpression' || node.type === 'LogicalExpression')); - declare export function isScopable(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'BlockStatement' || node.type === 'CatchClause' || node.type === 'DoWhileStatement' || node.type === 'ForInStatement' || node.type === 'ForStatement' || node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'Program' || node.type === 'ObjectMethod' || node.type === 'SwitchStatement' || node.type === 'WhileStatement' || node.type === 'ArrowFunctionExpression' || node.type === 'ClassExpression' || node.type === 'ClassDeclaration' || node.type === 'ForOfStatement' || node.type === 'ClassMethod' || node.type === 'ClassPrivateMethod' || node.type === 'StaticBlock' || node.type === 'TSModuleBlock')); - declare export function isBlockParent(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'BlockStatement' || node.type === 'CatchClause' || node.type === 'DoWhileStatement' || node.type === 'ForInStatement' || node.type === 'ForStatement' || node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'Program' || node.type === 'ObjectMethod' || node.type === 'SwitchStatement' || node.type === 'WhileStatement' || node.type === 'ArrowFunctionExpression' || node.type === 'ForOfStatement' || node.type === 'ClassMethod' || node.type === 'ClassPrivateMethod' || node.type === 'StaticBlock' || node.type === 'TSModuleBlock')); - declare export function isBlock(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'BlockStatement' || node.type === 'Program' || node.type === 'TSModuleBlock')); - declare export function isStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'BlockStatement' || node.type === 'BreakStatement' || node.type === 'ContinueStatement' || node.type === 'DebuggerStatement' || node.type === 'DoWhileStatement' || node.type === 'EmptyStatement' || node.type === 'ExpressionStatement' || node.type === 'ForInStatement' || node.type === 'ForStatement' || node.type === 'FunctionDeclaration' || node.type === 'IfStatement' || node.type === 'LabeledStatement' || node.type === 'ReturnStatement' || node.type === 'SwitchStatement' || node.type === 'ThrowStatement' || node.type === 'TryStatement' || node.type === 'VariableDeclaration' || node.type === 'WhileStatement' || node.type === 'WithStatement' || node.type === 'ClassDeclaration' || node.type === 'ExportAllDeclaration' || node.type === 'ExportDefaultDeclaration' || node.type === 'ExportNamedDeclaration' || node.type === 'ForOfStatement' || node.type === 'ImportDeclaration' || node.type === 'DeclareClass' || node.type === 'DeclareFunction' || node.type === 'DeclareInterface' || node.type === 'DeclareModule' || node.type === 'DeclareModuleExports' || node.type === 'DeclareTypeAlias' || node.type === 'DeclareOpaqueType' || node.type === 'DeclareVariable' || node.type === 'DeclareExportDeclaration' || node.type === 'DeclareExportAllDeclaration' || node.type === 'InterfaceDeclaration' || node.type === 'OpaqueType' || node.type === 'TypeAlias' || node.type === 'EnumDeclaration' || node.type === 'TSDeclareFunction' || node.type === 'TSInterfaceDeclaration' || node.type === 'TSTypeAliasDeclaration' || node.type === 'TSEnumDeclaration' || node.type === 'TSModuleDeclaration' || node.type === 'TSImportEqualsDeclaration' || node.type === 'TSExportAssignment' || node.type === 'TSNamespaceExportDeclaration')); - declare export function isTerminatorless(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'BreakStatement' || node.type === 'ContinueStatement' || node.type === 'ReturnStatement' || node.type === 'ThrowStatement' || node.type === 'YieldExpression' || node.type === 'AwaitExpression')); - declare export function isCompletionStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'BreakStatement' || node.type === 'ContinueStatement' || node.type === 'ReturnStatement' || node.type === 'ThrowStatement')); - declare export function isConditional(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ConditionalExpression' || node.type === 'IfStatement')); - declare export function isLoop(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'DoWhileStatement' || node.type === 'ForInStatement' || node.type === 'ForStatement' || node.type === 'WhileStatement' || node.type === 'ForOfStatement')); - declare export function isWhile(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'DoWhileStatement' || node.type === 'WhileStatement')); - declare export function isExpressionWrapper(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ExpressionStatement' || node.type === 'ParenthesizedExpression' || node.type === 'TypeCastExpression')); - declare export function isFor(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ForInStatement' || node.type === 'ForStatement' || node.type === 'ForOfStatement')); - declare export function isForXStatement(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ForInStatement' || node.type === 'ForOfStatement')); - declare export function isFunction(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ObjectMethod' || node.type === 'ArrowFunctionExpression' || node.type === 'ClassMethod' || node.type === 'ClassPrivateMethod')); - declare export function isFunctionParent(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ObjectMethod' || node.type === 'ArrowFunctionExpression' || node.type === 'ClassMethod' || node.type === 'ClassPrivateMethod' || node.type === 'StaticBlock' || node.type === 'TSModuleBlock')); - declare export function isPureish(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'StringLiteral' || node.type === 'NumericLiteral' || node.type === 'NullLiteral' || node.type === 'BooleanLiteral' || node.type === 'RegExpLiteral' || node.type === 'ArrowFunctionExpression' || node.type === 'BigIntLiteral' || node.type === 'DecimalLiteral')); - declare export function isDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'FunctionDeclaration' || node.type === 'VariableDeclaration' || node.type === 'ClassDeclaration' || node.type === 'ExportAllDeclaration' || node.type === 'ExportDefaultDeclaration' || node.type === 'ExportNamedDeclaration' || node.type === 'ImportDeclaration' || node.type === 'DeclareClass' || node.type === 'DeclareFunction' || node.type === 'DeclareInterface' || node.type === 'DeclareModule' || node.type === 'DeclareModuleExports' || node.type === 'DeclareTypeAlias' || node.type === 'DeclareOpaqueType' || node.type === 'DeclareVariable' || node.type === 'DeclareExportDeclaration' || node.type === 'DeclareExportAllDeclaration' || node.type === 'InterfaceDeclaration' || node.type === 'OpaqueType' || node.type === 'TypeAlias' || node.type === 'EnumDeclaration' || node.type === 'TSDeclareFunction' || node.type === 'TSInterfaceDeclaration' || node.type === 'TSTypeAliasDeclaration' || node.type === 'TSEnumDeclaration' || node.type === 'TSModuleDeclaration')); - declare export function isPatternLike(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'Identifier' || node.type === 'RestElement' || node.type === 'AssignmentPattern' || node.type === 'ArrayPattern' || node.type === 'ObjectPattern' || node.type === 'TSAsExpression' || node.type === 'TSSatisfiesExpression' || node.type === 'TSTypeAssertion' || node.type === 'TSNonNullExpression')); - declare export function isLVal(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'Identifier' || node.type === 'MemberExpression' || node.type === 'RestElement' || node.type === 'AssignmentPattern' || node.type === 'ArrayPattern' || node.type === 'ObjectPattern' || node.type === 'TSParameterProperty' || node.type === 'TSAsExpression' || node.type === 'TSSatisfiesExpression' || node.type === 'TSTypeAssertion' || node.type === 'TSNonNullExpression')); - declare export function isTSEntityName(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'Identifier' || node.type === 'TSQualifiedName')); - declare export function isLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'StringLiteral' || node.type === 'NumericLiteral' || node.type === 'NullLiteral' || node.type === 'BooleanLiteral' || node.type === 'RegExpLiteral' || node.type === 'TemplateLiteral' || node.type === 'BigIntLiteral' || node.type === 'DecimalLiteral')); - declare export function isImmutable(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'StringLiteral' || node.type === 'NumericLiteral' || node.type === 'NullLiteral' || node.type === 'BooleanLiteral' || node.type === 'BigIntLiteral' || node.type === 'JSXAttribute' || node.type === 'JSXClosingElement' || node.type === 'JSXElement' || node.type === 'JSXExpressionContainer' || node.type === 'JSXSpreadChild' || node.type === 'JSXOpeningElement' || node.type === 'JSXText' || node.type === 'JSXFragment' || node.type === 'JSXOpeningFragment' || node.type === 'JSXClosingFragment' || node.type === 'DecimalLiteral')); - declare export function isUserWhitespacable(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ObjectMethod' || node.type === 'ObjectProperty' || node.type === 'ObjectTypeInternalSlot' || node.type === 'ObjectTypeCallProperty' || node.type === 'ObjectTypeIndexer' || node.type === 'ObjectTypeProperty' || node.type === 'ObjectTypeSpreadProperty')); - declare export function isMethod(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ObjectMethod' || node.type === 'ClassMethod' || node.type === 'ClassPrivateMethod')); - declare export function isObjectMember(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ObjectMethod' || node.type === 'ObjectProperty')); - declare export function isProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ObjectProperty' || node.type === 'ClassProperty' || node.type === 'ClassAccessorProperty' || node.type === 'ClassPrivateProperty')); - declare export function isUnaryLike(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'UnaryExpression' || node.type === 'SpreadElement')); - declare export function isPattern(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'AssignmentPattern' || node.type === 'ArrayPattern' || node.type === 'ObjectPattern')); - declare export function isClass(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ClassExpression' || node.type === 'ClassDeclaration')); - declare export function isModuleDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ExportAllDeclaration' || node.type === 'ExportDefaultDeclaration' || node.type === 'ExportNamedDeclaration' || node.type === 'ImportDeclaration')); - declare export function isExportDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ExportAllDeclaration' || node.type === 'ExportDefaultDeclaration' || node.type === 'ExportNamedDeclaration')); - declare export function isModuleSpecifier(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ExportSpecifier' || node.type === 'ImportDefaultSpecifier' || node.type === 'ImportNamespaceSpecifier' || node.type === 'ImportSpecifier' || node.type === 'ExportNamespaceSpecifier' || node.type === 'ExportDefaultSpecifier')); - declare export function isAccessor(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ClassAccessorProperty')); - declare export function isPrivate(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'ClassPrivateProperty' || node.type === 'ClassPrivateMethod' || node.type === 'PrivateName')); - declare export function isFlow(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'AnyTypeAnnotation' || node.type === 'ArrayTypeAnnotation' || node.type === 'BooleanTypeAnnotation' || node.type === 'BooleanLiteralTypeAnnotation' || node.type === 'NullLiteralTypeAnnotation' || node.type === 'ClassImplements' || node.type === 'DeclareClass' || node.type === 'DeclareFunction' || node.type === 'DeclareInterface' || node.type === 'DeclareModule' || node.type === 'DeclareModuleExports' || node.type === 'DeclareTypeAlias' || node.type === 'DeclareOpaqueType' || node.type === 'DeclareVariable' || node.type === 'DeclareExportDeclaration' || node.type === 'DeclareExportAllDeclaration' || node.type === 'DeclaredPredicate' || node.type === 'ExistsTypeAnnotation' || node.type === 'FunctionTypeAnnotation' || node.type === 'FunctionTypeParam' || node.type === 'GenericTypeAnnotation' || node.type === 'InferredPredicate' || node.type === 'InterfaceExtends' || node.type === 'InterfaceDeclaration' || node.type === 'InterfaceTypeAnnotation' || node.type === 'IntersectionTypeAnnotation' || node.type === 'MixedTypeAnnotation' || node.type === 'EmptyTypeAnnotation' || node.type === 'NullableTypeAnnotation' || node.type === 'NumberLiteralTypeAnnotation' || node.type === 'NumberTypeAnnotation' || node.type === 'ObjectTypeAnnotation' || node.type === 'ObjectTypeInternalSlot' || node.type === 'ObjectTypeCallProperty' || node.type === 'ObjectTypeIndexer' || node.type === 'ObjectTypeProperty' || node.type === 'ObjectTypeSpreadProperty' || node.type === 'OpaqueType' || node.type === 'QualifiedTypeIdentifier' || node.type === 'StringLiteralTypeAnnotation' || node.type === 'StringTypeAnnotation' || node.type === 'SymbolTypeAnnotation' || node.type === 'ThisTypeAnnotation' || node.type === 'TupleTypeAnnotation' || node.type === 'TypeofTypeAnnotation' || node.type === 'TypeAlias' || node.type === 'TypeAnnotation' || node.type === 'TypeCastExpression' || node.type === 'TypeParameter' || node.type === 'TypeParameterDeclaration' || node.type === 'TypeParameterInstantiation' || node.type === 'UnionTypeAnnotation' || node.type === 'Variance' || node.type === 'VoidTypeAnnotation' || node.type === 'EnumDeclaration' || node.type === 'EnumBooleanBody' || node.type === 'EnumNumberBody' || node.type === 'EnumStringBody' || node.type === 'EnumSymbolBody' || node.type === 'EnumBooleanMember' || node.type === 'EnumNumberMember' || node.type === 'EnumStringMember' || node.type === 'EnumDefaultedMember' || node.type === 'IndexedAccessType' || node.type === 'OptionalIndexedAccessType')); - declare export function isFlowType(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'AnyTypeAnnotation' || node.type === 'ArrayTypeAnnotation' || node.type === 'BooleanTypeAnnotation' || node.type === 'BooleanLiteralTypeAnnotation' || node.type === 'NullLiteralTypeAnnotation' || node.type === 'ExistsTypeAnnotation' || node.type === 'FunctionTypeAnnotation' || node.type === 'GenericTypeAnnotation' || node.type === 'InterfaceTypeAnnotation' || node.type === 'IntersectionTypeAnnotation' || node.type === 'MixedTypeAnnotation' || node.type === 'EmptyTypeAnnotation' || node.type === 'NullableTypeAnnotation' || node.type === 'NumberLiteralTypeAnnotation' || node.type === 'NumberTypeAnnotation' || node.type === 'ObjectTypeAnnotation' || node.type === 'StringLiteralTypeAnnotation' || node.type === 'StringTypeAnnotation' || node.type === 'SymbolTypeAnnotation' || node.type === 'ThisTypeAnnotation' || node.type === 'TupleTypeAnnotation' || node.type === 'TypeofTypeAnnotation' || node.type === 'UnionTypeAnnotation' || node.type === 'VoidTypeAnnotation' || node.type === 'IndexedAccessType' || node.type === 'OptionalIndexedAccessType')); - declare export function isFlowBaseAnnotation(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'AnyTypeAnnotation' || node.type === 'BooleanTypeAnnotation' || node.type === 'NullLiteralTypeAnnotation' || node.type === 'MixedTypeAnnotation' || node.type === 'EmptyTypeAnnotation' || node.type === 'NumberTypeAnnotation' || node.type === 'StringTypeAnnotation' || node.type === 'SymbolTypeAnnotation' || node.type === 'ThisTypeAnnotation' || node.type === 'VoidTypeAnnotation')); - declare export function isFlowDeclaration(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'DeclareClass' || node.type === 'DeclareFunction' || node.type === 'DeclareInterface' || node.type === 'DeclareModule' || node.type === 'DeclareModuleExports' || node.type === 'DeclareTypeAlias' || node.type === 'DeclareOpaqueType' || node.type === 'DeclareVariable' || node.type === 'DeclareExportDeclaration' || node.type === 'DeclareExportAllDeclaration' || node.type === 'InterfaceDeclaration' || node.type === 'OpaqueType' || node.type === 'TypeAlias')); - declare export function isFlowPredicate(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'DeclaredPredicate' || node.type === 'InferredPredicate')); - declare export function isEnumBody(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'EnumBooleanBody' || node.type === 'EnumNumberBody' || node.type === 'EnumStringBody' || node.type === 'EnumSymbolBody')); - declare export function isEnumMember(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'EnumBooleanMember' || node.type === 'EnumNumberMember' || node.type === 'EnumStringMember' || node.type === 'EnumDefaultedMember')); - declare export function isJSX(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'JSXAttribute' || node.type === 'JSXClosingElement' || node.type === 'JSXElement' || node.type === 'JSXEmptyExpression' || node.type === 'JSXExpressionContainer' || node.type === 'JSXSpreadChild' || node.type === 'JSXIdentifier' || node.type === 'JSXMemberExpression' || node.type === 'JSXNamespacedName' || node.type === 'JSXOpeningElement' || node.type === 'JSXSpreadAttribute' || node.type === 'JSXText' || node.type === 'JSXFragment' || node.type === 'JSXOpeningFragment' || node.type === 'JSXClosingFragment')); - declare export function isMiscellaneous(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'Noop' || node.type === 'Placeholder' || node.type === 'V8IntrinsicIdentifier')); - declare export function isTypeScript(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'TSParameterProperty' || node.type === 'TSDeclareFunction' || node.type === 'TSDeclareMethod' || node.type === 'TSQualifiedName' || node.type === 'TSCallSignatureDeclaration' || node.type === 'TSConstructSignatureDeclaration' || node.type === 'TSPropertySignature' || node.type === 'TSMethodSignature' || node.type === 'TSIndexSignature' || node.type === 'TSAnyKeyword' || node.type === 'TSBooleanKeyword' || node.type === 'TSBigIntKeyword' || node.type === 'TSIntrinsicKeyword' || node.type === 'TSNeverKeyword' || node.type === 'TSNullKeyword' || node.type === 'TSNumberKeyword' || node.type === 'TSObjectKeyword' || node.type === 'TSStringKeyword' || node.type === 'TSSymbolKeyword' || node.type === 'TSUndefinedKeyword' || node.type === 'TSUnknownKeyword' || node.type === 'TSVoidKeyword' || node.type === 'TSThisType' || node.type === 'TSFunctionType' || node.type === 'TSConstructorType' || node.type === 'TSTypeReference' || node.type === 'TSTypePredicate' || node.type === 'TSTypeQuery' || node.type === 'TSTypeLiteral' || node.type === 'TSArrayType' || node.type === 'TSTupleType' || node.type === 'TSOptionalType' || node.type === 'TSRestType' || node.type === 'TSNamedTupleMember' || node.type === 'TSUnionType' || node.type === 'TSIntersectionType' || node.type === 'TSConditionalType' || node.type === 'TSInferType' || node.type === 'TSParenthesizedType' || node.type === 'TSTypeOperator' || node.type === 'TSIndexedAccessType' || node.type === 'TSMappedType' || node.type === 'TSLiteralType' || node.type === 'TSExpressionWithTypeArguments' || node.type === 'TSInterfaceDeclaration' || node.type === 'TSInterfaceBody' || node.type === 'TSTypeAliasDeclaration' || node.type === 'TSInstantiationExpression' || node.type === 'TSAsExpression' || node.type === 'TSSatisfiesExpression' || node.type === 'TSTypeAssertion' || node.type === 'TSEnumDeclaration' || node.type === 'TSEnumMember' || node.type === 'TSModuleDeclaration' || node.type === 'TSModuleBlock' || node.type === 'TSImportType' || node.type === 'TSImportEqualsDeclaration' || node.type === 'TSExternalModuleReference' || node.type === 'TSNonNullExpression' || node.type === 'TSExportAssignment' || node.type === 'TSNamespaceExportDeclaration' || node.type === 'TSTypeAnnotation' || node.type === 'TSTypeParameterInstantiation' || node.type === 'TSTypeParameterDeclaration' || node.type === 'TSTypeParameter')); - declare export function isTSTypeElement(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'TSCallSignatureDeclaration' || node.type === 'TSConstructSignatureDeclaration' || node.type === 'TSPropertySignature' || node.type === 'TSMethodSignature' || node.type === 'TSIndexSignature')); - declare export function isTSType(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'TSAnyKeyword' || node.type === 'TSBooleanKeyword' || node.type === 'TSBigIntKeyword' || node.type === 'TSIntrinsicKeyword' || node.type === 'TSNeverKeyword' || node.type === 'TSNullKeyword' || node.type === 'TSNumberKeyword' || node.type === 'TSObjectKeyword' || node.type === 'TSStringKeyword' || node.type === 'TSSymbolKeyword' || node.type === 'TSUndefinedKeyword' || node.type === 'TSUnknownKeyword' || node.type === 'TSVoidKeyword' || node.type === 'TSThisType' || node.type === 'TSFunctionType' || node.type === 'TSConstructorType' || node.type === 'TSTypeReference' || node.type === 'TSTypePredicate' || node.type === 'TSTypeQuery' || node.type === 'TSTypeLiteral' || node.type === 'TSArrayType' || node.type === 'TSTupleType' || node.type === 'TSOptionalType' || node.type === 'TSRestType' || node.type === 'TSUnionType' || node.type === 'TSIntersectionType' || node.type === 'TSConditionalType' || node.type === 'TSInferType' || node.type === 'TSParenthesizedType' || node.type === 'TSTypeOperator' || node.type === 'TSIndexedAccessType' || node.type === 'TSMappedType' || node.type === 'TSLiteralType' || node.type === 'TSExpressionWithTypeArguments' || node.type === 'TSImportType')); - declare export function isTSBaseType(node: ?Object, opts?: ?Object): boolean %checks (node != null && (node.type === 'TSAnyKeyword' || node.type === 'TSBooleanKeyword' || node.type === 'TSBigIntKeyword' || node.type === 'TSIntrinsicKeyword' || node.type === 'TSNeverKeyword' || node.type === 'TSNullKeyword' || node.type === 'TSNumberKeyword' || node.type === 'TSObjectKeyword' || node.type === 'TSStringKeyword' || node.type === 'TSSymbolKeyword' || node.type === 'TSUndefinedKeyword' || node.type === 'TSUnknownKeyword' || node.type === 'TSVoidKeyword' || node.type === 'TSThisType' || node.type === 'TSLiteralType')); - declare export function isNumberLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'NumericLiteral'); - declare export function isRegexLiteral(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'RegExpLiteral'); - declare export function isRestProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'RestElement'); - declare export function isSpreadProperty(node: ?Object, opts?: ?Object): boolean %checks (node != null && node.type === 'SpreadElement'); + declare export function isArrayExpression(node: ?Object, opts?: ?Object): node is ArrayExpression; + declare export function isAssignmentExpression(node: ?Object, opts?: ?Object): node is AssignmentExpression; + declare export function isBinaryExpression(node: ?Object, opts?: ?Object): node is BinaryExpression; + declare export function isInterpreterDirective(node: ?Object, opts?: ?Object): node is InterpreterDirective; + declare export function isDirective(node: ?Object, opts?: ?Object): node is Directive; + declare export function isDirectiveLiteral(node: ?Object, opts?: ?Object): node is DirectiveLiteral; + declare export function isBlockStatement(node: ?Object, opts?: ?Object): node is BlockStatement; + declare export function isBreakStatement(node: ?Object, opts?: ?Object): node is BreakStatement; + declare export function isCallExpression(node: ?Object, opts?: ?Object): node is CallExpression; + declare export function isCatchClause(node: ?Object, opts?: ?Object): node is CatchClause; + declare export function isConditionalExpression(node: ?Object, opts?: ?Object): node is ConditionalExpression; + declare export function isContinueStatement(node: ?Object, opts?: ?Object): node is ContinueStatement; + declare export function isDebuggerStatement(node: ?Object, opts?: ?Object): node is DebuggerStatement; + declare export function isDoWhileStatement(node: ?Object, opts?: ?Object): node is DoWhileStatement; + declare export function isEmptyStatement(node: ?Object, opts?: ?Object): node is EmptyStatement; + declare export function isExpressionStatement(node: ?Object, opts?: ?Object): node is ExpressionStatement; + declare export function isFile(node: ?Object, opts?: ?Object): node is File; + declare export function isForInStatement(node: ?Object, opts?: ?Object): node is ForInStatement; + declare export function isForStatement(node: ?Object, opts?: ?Object): node is ForStatement; + declare export function isFunctionDeclaration(node: ?Object, opts?: ?Object): node is FunctionDeclaration; + declare export function isFunctionExpression(node: ?Object, opts?: ?Object): node is FunctionExpression; + declare export function isIdentifier(node: ?Object, opts?: ?Object): node is Identifier; + declare export function isIfStatement(node: ?Object, opts?: ?Object): node is IfStatement; + declare export function isLabeledStatement(node: ?Object, opts?: ?Object): node is LabeledStatement; + declare export function isStringLiteral(node: ?Object, opts?: ?Object): node is StringLiteral; + declare export function isNumericLiteral(node: ?Object, opts?: ?Object): node is NumericLiteral; + declare export function isNullLiteral(node: ?Object, opts?: ?Object): node is NullLiteral; + declare export function isBooleanLiteral(node: ?Object, opts?: ?Object): node is BooleanLiteral; + declare export function isRegExpLiteral(node: ?Object, opts?: ?Object): node is RegExpLiteral; + declare export function isLogicalExpression(node: ?Object, opts?: ?Object): node is LogicalExpression; + declare export function isMemberExpression(node: ?Object, opts?: ?Object): node is MemberExpression; + declare export function isNewExpression(node: ?Object, opts?: ?Object): node is NewExpression; + declare export function isProgram(node: ?Object, opts?: ?Object): node is Program; + declare export function isObjectExpression(node: ?Object, opts?: ?Object): node is ObjectExpression; + declare export function isObjectMethod(node: ?Object, opts?: ?Object): node is ObjectMethod; + declare export function isObjectProperty(node: ?Object, opts?: ?Object): node is ObjectProperty; + declare export function isRestElement(node: ?Object, opts?: ?Object): node is RestElement; + declare export function isReturnStatement(node: ?Object, opts?: ?Object): node is ReturnStatement; + declare export function isSequenceExpression(node: ?Object, opts?: ?Object): node is SequenceExpression; + declare export function isParenthesizedExpression(node: ?Object, opts?: ?Object): node is ParenthesizedExpression; + declare export function isSwitchCase(node: ?Object, opts?: ?Object): node is SwitchCase; + declare export function isSwitchStatement(node: ?Object, opts?: ?Object): node is SwitchStatement; + declare export function isThisExpression(node: ?Object, opts?: ?Object): node is ThisExpression; + declare export function isThrowStatement(node: ?Object, opts?: ?Object): node is ThrowStatement; + declare export function isTryStatement(node: ?Object, opts?: ?Object): node is TryStatement; + declare export function isUnaryExpression(node: ?Object, opts?: ?Object): node is UnaryExpression; + declare export function isUpdateExpression(node: ?Object, opts?: ?Object): node is UpdateExpression; + declare export function isVariableDeclaration(node: ?Object, opts?: ?Object): node is VariableDeclaration; + declare export function isVariableDeclarator(node: ?Object, opts?: ?Object): node is VariableDeclarator; + declare export function isWhileStatement(node: ?Object, opts?: ?Object): node is WhileStatement; + declare export function isWithStatement(node: ?Object, opts?: ?Object): node is WithStatement; + declare export function isAssignmentPattern(node: ?Object, opts?: ?Object): node is AssignmentPattern; + declare export function isArrayPattern(node: ?Object, opts?: ?Object): node is ArrayPattern; + declare export function isArrowFunctionExpression(node: ?Object, opts?: ?Object): node is ArrowFunctionExpression; + declare export function isClassBody(node: ?Object, opts?: ?Object): node is ClassBody; + declare export function isClassExpression(node: ?Object, opts?: ?Object): node is ClassExpression; + declare export function isClassDeclaration(node: ?Object, opts?: ?Object): node is ClassDeclaration; + declare export function isExportAllDeclaration(node: ?Object, opts?: ?Object): node is ExportAllDeclaration; + declare export function isExportDefaultDeclaration(node: ?Object, opts?: ?Object): node is ExportDefaultDeclaration; + declare export function isExportNamedDeclaration(node: ?Object, opts?: ?Object): node is ExportNamedDeclaration; + declare export function isExportSpecifier(node: ?Object, opts?: ?Object): node is ExportSpecifier; + declare export function isForOfStatement(node: ?Object, opts?: ?Object): node is ForOfStatement; + declare export function isImportDeclaration(node: ?Object, opts?: ?Object): node is ImportDeclaration; + declare export function isImportDefaultSpecifier(node: ?Object, opts?: ?Object): node is ImportDefaultSpecifier; + declare export function isImportNamespaceSpecifier(node: ?Object, opts?: ?Object): node is ImportNamespaceSpecifier; + declare export function isImportSpecifier(node: ?Object, opts?: ?Object): node is ImportSpecifier; + declare export function isMetaProperty(node: ?Object, opts?: ?Object): node is MetaProperty; + declare export function isClassMethod(node: ?Object, opts?: ?Object): node is ClassMethod; + declare export function isObjectPattern(node: ?Object, opts?: ?Object): node is ObjectPattern; + declare export function isSpreadElement(node: ?Object, opts?: ?Object): node is SpreadElement; + declare export function isSuper(node: ?Object, opts?: ?Object): node is Super; + declare export function isTaggedTemplateExpression(node: ?Object, opts?: ?Object): node is TaggedTemplateExpression; + declare export function isTemplateElement(node: ?Object, opts?: ?Object): node is TemplateElement; + declare export function isTemplateLiteral(node: ?Object, opts?: ?Object): node is TemplateLiteral; + declare export function isYieldExpression(node: ?Object, opts?: ?Object): node is YieldExpression; + declare export function isAwaitExpression(node: ?Object, opts?: ?Object): node is AwaitExpression; + declare export function isImport(node: ?Object, opts?: ?Object): node is Import; + declare export function isBigIntLiteral(node: ?Object, opts?: ?Object): node is BigIntLiteral; + declare export function isExportNamespaceSpecifier(node: ?Object, opts?: ?Object): node is ExportNamespaceSpecifier; + declare export function isOptionalMemberExpression(node: ?Object, opts?: ?Object): node is OptionalMemberExpression; + declare export function isOptionalCallExpression(node: ?Object, opts?: ?Object): node is OptionalCallExpression; + declare export function isClassProperty(node: ?Object, opts?: ?Object): node is ClassProperty; + declare export function isClassAccessorProperty(node: ?Object, opts?: ?Object): node is ClassAccessorProperty; + declare export function isClassPrivateProperty(node: ?Object, opts?: ?Object): node is ClassPrivateProperty; + declare export function isClassPrivateMethod(node: ?Object, opts?: ?Object): node is ClassPrivateMethod; + declare export function isPrivateName(node: ?Object, opts?: ?Object): node is PrivateName; + declare export function isStaticBlock(node: ?Object, opts?: ?Object): node is StaticBlock; + declare export function isAnyTypeAnnotation(node: ?Object, opts?: ?Object): node is AnyTypeAnnotation; + declare export function isArrayTypeAnnotation(node: ?Object, opts?: ?Object): node is ArrayTypeAnnotation; + declare export function isBooleanTypeAnnotation(node: ?Object, opts?: ?Object): node is BooleanTypeAnnotation; + declare export function isBooleanLiteralTypeAnnotation(node: ?Object, opts?: ?Object): node is BooleanLiteralTypeAnnotation; + declare export function isNullLiteralTypeAnnotation(node: ?Object, opts?: ?Object): node is NullLiteralTypeAnnotation; + declare export function isClassImplements(node: ?Object, opts?: ?Object): node is ClassImplements; + declare export function isDeclareClass(node: ?Object, opts?: ?Object): node is DeclareClass; + declare export function isDeclareFunction(node: ?Object, opts?: ?Object): node is DeclareFunction; + declare export function isDeclareInterface(node: ?Object, opts?: ?Object): node is DeclareInterface; + declare export function isDeclareModule(node: ?Object, opts?: ?Object): node is DeclareModule; + declare export function isDeclareModuleExports(node: ?Object, opts?: ?Object): node is DeclareModuleExports; + declare export function isDeclareTypeAlias(node: ?Object, opts?: ?Object): node is DeclareTypeAlias; + declare export function isDeclareOpaqueType(node: ?Object, opts?: ?Object): node is DeclareOpaqueType; + declare export function isDeclareVariable(node: ?Object, opts?: ?Object): node is DeclareVariable; + declare export function isDeclareExportDeclaration(node: ?Object, opts?: ?Object): node is DeclareExportDeclaration; + declare export function isDeclareExportAllDeclaration(node: ?Object, opts?: ?Object): node is DeclareExportAllDeclaration; + declare export function isDeclaredPredicate(node: ?Object, opts?: ?Object): node is DeclaredPredicate; + declare export function isExistsTypeAnnotation(node: ?Object, opts?: ?Object): node is ExistsTypeAnnotation; + declare export function isFunctionTypeAnnotation(node: ?Object, opts?: ?Object): node is FunctionTypeAnnotation; + declare export function isFunctionTypeParam(node: ?Object, opts?: ?Object): node is FunctionTypeParam; + declare export function isGenericTypeAnnotation(node: ?Object, opts?: ?Object): node is GenericTypeAnnotation; + declare export function isInferredPredicate(node: ?Object, opts?: ?Object): node is InferredPredicate; + declare export function isInterfaceExtends(node: ?Object, opts?: ?Object): node is InterfaceExtends; + declare export function isInterfaceDeclaration(node: ?Object, opts?: ?Object): node is InterfaceDeclaration; + declare export function isInterfaceTypeAnnotation(node: ?Object, opts?: ?Object): node is InterfaceTypeAnnotation; + declare export function isIntersectionTypeAnnotation(node: ?Object, opts?: ?Object): node is IntersectionTypeAnnotation; + declare export function isMixedTypeAnnotation(node: ?Object, opts?: ?Object): node is MixedTypeAnnotation; + declare export function isEmptyTypeAnnotation(node: ?Object, opts?: ?Object): node is EmptyTypeAnnotation; + declare export function isNullableTypeAnnotation(node: ?Object, opts?: ?Object): node is NullableTypeAnnotation; + declare export function isNumberLiteralTypeAnnotation(node: ?Object, opts?: ?Object): node is NumberLiteralTypeAnnotation; + declare export function isNumberTypeAnnotation(node: ?Object, opts?: ?Object): node is NumberTypeAnnotation; + declare export function isObjectTypeAnnotation(node: ?Object, opts?: ?Object): node is ObjectTypeAnnotation; + declare export function isObjectTypeInternalSlot(node: ?Object, opts?: ?Object): node is ObjectTypeInternalSlot; + declare export function isObjectTypeCallProperty(node: ?Object, opts?: ?Object): node is ObjectTypeCallProperty; + declare export function isObjectTypeIndexer(node: ?Object, opts?: ?Object): node is ObjectTypeIndexer; + declare export function isObjectTypeProperty(node: ?Object, opts?: ?Object): node is ObjectTypeProperty; + declare export function isObjectTypeSpreadProperty(node: ?Object, opts?: ?Object): node is ObjectTypeSpreadProperty; + declare export function isOpaqueType(node: ?Object, opts?: ?Object): node is OpaqueType; + declare export function isQualifiedTypeIdentifier(node: ?Object, opts?: ?Object): node is QualifiedTypeIdentifier; + declare export function isStringLiteralTypeAnnotation(node: ?Object, opts?: ?Object): node is StringLiteralTypeAnnotation; + declare export function isStringTypeAnnotation(node: ?Object, opts?: ?Object): node is StringTypeAnnotation; + declare export function isSymbolTypeAnnotation(node: ?Object, opts?: ?Object): node is SymbolTypeAnnotation; + declare export function isThisTypeAnnotation(node: ?Object, opts?: ?Object): node is ThisTypeAnnotation; + declare export function isTupleTypeAnnotation(node: ?Object, opts?: ?Object): node is TupleTypeAnnotation; + declare export function isTypeofTypeAnnotation(node: ?Object, opts?: ?Object): node is TypeofTypeAnnotation; + declare export function isTypeAlias(node: ?Object, opts?: ?Object): node is TypeAlias; + declare export function isTypeAnnotation(node: ?Object, opts?: ?Object): node is TypeAnnotation; + declare export function isTypeCastExpression(node: ?Object, opts?: ?Object): node is TypeCastExpression; + declare export function isTypeParameter(node: ?Object, opts?: ?Object): node is TypeParameter; + declare export function isTypeParameterDeclaration(node: ?Object, opts?: ?Object): node is TypeParameterDeclaration; + declare export function isTypeParameterInstantiation(node: ?Object, opts?: ?Object): node is TypeParameterInstantiation; + declare export function isUnionTypeAnnotation(node: ?Object, opts?: ?Object): node is UnionTypeAnnotation; + declare export function isVariance(node: ?Object, opts?: ?Object): node is Variance; + declare export function isVoidTypeAnnotation(node: ?Object, opts?: ?Object): node is VoidTypeAnnotation; + declare export function isEnumDeclaration(node: ?Object, opts?: ?Object): node is EnumDeclaration; + declare export function isEnumBooleanBody(node: ?Object, opts?: ?Object): node is EnumBooleanBody; + declare export function isEnumNumberBody(node: ?Object, opts?: ?Object): node is EnumNumberBody; + declare export function isEnumStringBody(node: ?Object, opts?: ?Object): node is EnumStringBody; + declare export function isEnumSymbolBody(node: ?Object, opts?: ?Object): node is EnumSymbolBody; + declare export function isEnumBooleanMember(node: ?Object, opts?: ?Object): node is EnumBooleanMember; + declare export function isEnumNumberMember(node: ?Object, opts?: ?Object): node is EnumNumberMember; + declare export function isEnumStringMember(node: ?Object, opts?: ?Object): node is EnumStringMember; + declare export function isEnumDefaultedMember(node: ?Object, opts?: ?Object): node is EnumDefaultedMember; + declare export function isIndexedAccessType(node: ?Object, opts?: ?Object): node is IndexedAccessType; + declare export function isOptionalIndexedAccessType(node: ?Object, opts?: ?Object): node is OptionalIndexedAccessType; + declare export function isJSXAttribute(node: ?Object, opts?: ?Object): node is JSXAttribute; + declare export function isJSXClosingElement(node: ?Object, opts?: ?Object): node is JSXClosingElement; + declare export function isJSXElement(node: ?Object, opts?: ?Object): node is JSXElement; + declare export function isJSXEmptyExpression(node: ?Object, opts?: ?Object): node is JSXEmptyExpression; + declare export function isJSXExpressionContainer(node: ?Object, opts?: ?Object): node is JSXExpressionContainer; + declare export function isJSXSpreadChild(node: ?Object, opts?: ?Object): node is JSXSpreadChild; + declare export function isJSXIdentifier(node: ?Object, opts?: ?Object): node is JSXIdentifier; + declare export function isJSXMemberExpression(node: ?Object, opts?: ?Object): node is JSXMemberExpression; + declare export function isJSXNamespacedName(node: ?Object, opts?: ?Object): node is JSXNamespacedName; + declare export function isJSXOpeningElement(node: ?Object, opts?: ?Object): node is JSXOpeningElement; + declare export function isJSXSpreadAttribute(node: ?Object, opts?: ?Object): node is JSXSpreadAttribute; + declare export function isJSXText(node: ?Object, opts?: ?Object): node is JSXText; + declare export function isJSXFragment(node: ?Object, opts?: ?Object): node is JSXFragment; + declare export function isJSXOpeningFragment(node: ?Object, opts?: ?Object): node is JSXOpeningFragment; + declare export function isJSXClosingFragment(node: ?Object, opts?: ?Object): node is JSXClosingFragment; + declare export function isNoop(node: ?Object, opts?: ?Object): node is Noop; + declare export function isPlaceholder(node: ?Object, opts?: ?Object): node is Placeholder; + declare export function isV8IntrinsicIdentifier(node: ?Object, opts?: ?Object): node is V8IntrinsicIdentifier; + declare export function isArgumentPlaceholder(node: ?Object, opts?: ?Object): node is ArgumentPlaceholder; + declare export function isBindExpression(node: ?Object, opts?: ?Object): node is BindExpression; + declare export function isImportAttribute(node: ?Object, opts?: ?Object): node is ImportAttribute; + declare export function isDecorator(node: ?Object, opts?: ?Object): node is Decorator; + declare export function isDoExpression(node: ?Object, opts?: ?Object): node is DoExpression; + declare export function isExportDefaultSpecifier(node: ?Object, opts?: ?Object): node is ExportDefaultSpecifier; + declare export function isRecordExpression(node: ?Object, opts?: ?Object): node is RecordExpression; + declare export function isTupleExpression(node: ?Object, opts?: ?Object): node is TupleExpression; + declare export function isDecimalLiteral(node: ?Object, opts?: ?Object): node is DecimalLiteral; + declare export function isModuleExpression(node: ?Object, opts?: ?Object): node is ModuleExpression; + declare export function isTopicReference(node: ?Object, opts?: ?Object): node is TopicReference; + declare export function isPipelineTopicExpression(node: ?Object, opts?: ?Object): node is PipelineTopicExpression; + declare export function isPipelineBareFunction(node: ?Object, opts?: ?Object): node is PipelineBareFunction; + declare export function isPipelinePrimaryTopicReference(node: ?Object, opts?: ?Object): node is PipelinePrimaryTopicReference; + declare export function isTSParameterProperty(node: ?Object, opts?: ?Object): node is TSParameterProperty; + declare export function isTSDeclareFunction(node: ?Object, opts?: ?Object): node is TSDeclareFunction; + declare export function isTSDeclareMethod(node: ?Object, opts?: ?Object): node is TSDeclareMethod; + declare export function isTSQualifiedName(node: ?Object, opts?: ?Object): node is TSQualifiedName; + declare export function isTSCallSignatureDeclaration(node: ?Object, opts?: ?Object): node is TSCallSignatureDeclaration; + declare export function isTSConstructSignatureDeclaration(node: ?Object, opts?: ?Object): node is TSConstructSignatureDeclaration; + declare export function isTSPropertySignature(node: ?Object, opts?: ?Object): node is TSPropertySignature; + declare export function isTSMethodSignature(node: ?Object, opts?: ?Object): node is TSMethodSignature; + declare export function isTSIndexSignature(node: ?Object, opts?: ?Object): node is TSIndexSignature; + declare export function isTSAnyKeyword(node: ?Object, opts?: ?Object): node is TSAnyKeyword; + declare export function isTSBooleanKeyword(node: ?Object, opts?: ?Object): node is TSBooleanKeyword; + declare export function isTSBigIntKeyword(node: ?Object, opts?: ?Object): node is TSBigIntKeyword; + declare export function isTSIntrinsicKeyword(node: ?Object, opts?: ?Object): node is TSIntrinsicKeyword; + declare export function isTSNeverKeyword(node: ?Object, opts?: ?Object): node is TSNeverKeyword; + declare export function isTSNullKeyword(node: ?Object, opts?: ?Object): node is TSNullKeyword; + declare export function isTSNumberKeyword(node: ?Object, opts?: ?Object): node is TSNumberKeyword; + declare export function isTSObjectKeyword(node: ?Object, opts?: ?Object): node is TSObjectKeyword; + declare export function isTSStringKeyword(node: ?Object, opts?: ?Object): node is TSStringKeyword; + declare export function isTSSymbolKeyword(node: ?Object, opts?: ?Object): node is TSSymbolKeyword; + declare export function isTSUndefinedKeyword(node: ?Object, opts?: ?Object): node is TSUndefinedKeyword; + declare export function isTSUnknownKeyword(node: ?Object, opts?: ?Object): node is TSUnknownKeyword; + declare export function isTSVoidKeyword(node: ?Object, opts?: ?Object): node is TSVoidKeyword; + declare export function isTSThisType(node: ?Object, opts?: ?Object): node is TSThisType; + declare export function isTSFunctionType(node: ?Object, opts?: ?Object): node is TSFunctionType; + declare export function isTSConstructorType(node: ?Object, opts?: ?Object): node is TSConstructorType; + declare export function isTSTypeReference(node: ?Object, opts?: ?Object): node is TSTypeReference; + declare export function isTSTypePredicate(node: ?Object, opts?: ?Object): node is TSTypePredicate; + declare export function isTSTypeQuery(node: ?Object, opts?: ?Object): node is TSTypeQuery; + declare export function isTSTypeLiteral(node: ?Object, opts?: ?Object): node is TSTypeLiteral; + declare export function isTSArrayType(node: ?Object, opts?: ?Object): node is TSArrayType; + declare export function isTSTupleType(node: ?Object, opts?: ?Object): node is TSTupleType; + declare export function isTSOptionalType(node: ?Object, opts?: ?Object): node is TSOptionalType; + declare export function isTSRestType(node: ?Object, opts?: ?Object): node is TSRestType; + declare export function isTSNamedTupleMember(node: ?Object, opts?: ?Object): node is TSNamedTupleMember; + declare export function isTSUnionType(node: ?Object, opts?: ?Object): node is TSUnionType; + declare export function isTSIntersectionType(node: ?Object, opts?: ?Object): node is TSIntersectionType; + declare export function isTSConditionalType(node: ?Object, opts?: ?Object): node is TSConditionalType; + declare export function isTSInferType(node: ?Object, opts?: ?Object): node is TSInferType; + declare export function isTSParenthesizedType(node: ?Object, opts?: ?Object): node is TSParenthesizedType; + declare export function isTSTypeOperator(node: ?Object, opts?: ?Object): node is TSTypeOperator; + declare export function isTSIndexedAccessType(node: ?Object, opts?: ?Object): node is TSIndexedAccessType; + declare export function isTSMappedType(node: ?Object, opts?: ?Object): node is TSMappedType; + declare export function isTSLiteralType(node: ?Object, opts?: ?Object): node is TSLiteralType; + declare export function isTSExpressionWithTypeArguments(node: ?Object, opts?: ?Object): node is TSExpressionWithTypeArguments; + declare export function isTSInterfaceDeclaration(node: ?Object, opts?: ?Object): node is TSInterfaceDeclaration; + declare export function isTSInterfaceBody(node: ?Object, opts?: ?Object): node is TSInterfaceBody; + declare export function isTSTypeAliasDeclaration(node: ?Object, opts?: ?Object): node is TSTypeAliasDeclaration; + declare export function isTSInstantiationExpression(node: ?Object, opts?: ?Object): node is TSInstantiationExpression; + declare export function isTSAsExpression(node: ?Object, opts?: ?Object): node is TSAsExpression; + declare export function isTSSatisfiesExpression(node: ?Object, opts?: ?Object): node is TSSatisfiesExpression; + declare export function isTSTypeAssertion(node: ?Object, opts?: ?Object): node is TSTypeAssertion; + declare export function isTSEnumDeclaration(node: ?Object, opts?: ?Object): node is TSEnumDeclaration; + declare export function isTSEnumMember(node: ?Object, opts?: ?Object): node is TSEnumMember; + declare export function isTSModuleDeclaration(node: ?Object, opts?: ?Object): node is TSModuleDeclaration; + declare export function isTSModuleBlock(node: ?Object, opts?: ?Object): node is TSModuleBlock; + declare export function isTSImportType(node: ?Object, opts?: ?Object): node is TSImportType; + declare export function isTSImportEqualsDeclaration(node: ?Object, opts?: ?Object): node is TSImportEqualsDeclaration; + declare export function isTSExternalModuleReference(node: ?Object, opts?: ?Object): node is TSExternalModuleReference; + declare export function isTSNonNullExpression(node: ?Object, opts?: ?Object): node is TSNonNullExpression; + declare export function isTSExportAssignment(node: ?Object, opts?: ?Object): node is TSExportAssignment; + declare export function isTSNamespaceExportDeclaration(node: ?Object, opts?: ?Object): node is TSNamespaceExportDeclaration; + declare export function isTSTypeAnnotation(node: ?Object, opts?: ?Object): node is TSTypeAnnotation; + declare export function isTSTypeParameterInstantiation(node: ?Object, opts?: ?Object): node is TSTypeParameterInstantiation; + declare export function isTSTypeParameterDeclaration(node: ?Object, opts?: ?Object): node is TSTypeParameterDeclaration; + declare export function isTSTypeParameter(node: ?Object, opts?: ?Object): node is TSTypeParameter; + declare export function isStandardized(node: ?Object, opts?: ?Object): node is (ArrayExpression | AssignmentExpression | BinaryExpression | InterpreterDirective | Directive | DirectiveLiteral | BlockStatement | BreakStatement | CallExpression | CatchClause | ConditionalExpression | ContinueStatement | DebuggerStatement | DoWhileStatement | EmptyStatement | ExpressionStatement | File | ForInStatement | ForStatement | FunctionDeclaration | FunctionExpression | Identifier | IfStatement | LabeledStatement | StringLiteral | NumericLiteral | NullLiteral | BooleanLiteral | RegExpLiteral | LogicalExpression | MemberExpression | NewExpression | Program | ObjectExpression | ObjectMethod | ObjectProperty | RestElement | ReturnStatement | SequenceExpression | ParenthesizedExpression | SwitchCase | SwitchStatement | ThisExpression | ThrowStatement | TryStatement | UnaryExpression | UpdateExpression | VariableDeclaration | VariableDeclarator | WhileStatement | WithStatement | AssignmentPattern | ArrayPattern | ArrowFunctionExpression | ClassBody | ClassExpression | ClassDeclaration | ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration | ExportSpecifier | ForOfStatement | ImportDeclaration | ImportDefaultSpecifier | ImportNamespaceSpecifier | ImportSpecifier | MetaProperty | ClassMethod | ObjectPattern | SpreadElement | Super | TaggedTemplateExpression | TemplateElement | TemplateLiteral | YieldExpression | AwaitExpression | Import | BigIntLiteral | ExportNamespaceSpecifier | OptionalMemberExpression | OptionalCallExpression | ClassProperty | ClassAccessorProperty | ClassPrivateProperty | ClassPrivateMethod | PrivateName | StaticBlock); + declare export function isExpression(node: ?Object, opts?: ?Object): node is (ArrayExpression | AssignmentExpression | BinaryExpression | CallExpression | ConditionalExpression | FunctionExpression | Identifier | StringLiteral | NumericLiteral | NullLiteral | BooleanLiteral | RegExpLiteral | LogicalExpression | MemberExpression | NewExpression | ObjectExpression | SequenceExpression | ParenthesizedExpression | ThisExpression | UnaryExpression | UpdateExpression | ArrowFunctionExpression | ClassExpression | MetaProperty | Super | TaggedTemplateExpression | TemplateLiteral | YieldExpression | AwaitExpression | Import | BigIntLiteral | OptionalMemberExpression | OptionalCallExpression | TypeCastExpression | JSXElement | JSXFragment | BindExpression | DoExpression | RecordExpression | TupleExpression | DecimalLiteral | ModuleExpression | TopicReference | PipelineTopicExpression | PipelineBareFunction | PipelinePrimaryTopicReference | TSInstantiationExpression | TSAsExpression | TSSatisfiesExpression | TSTypeAssertion | TSNonNullExpression); + declare export function isBinary(node: ?Object, opts?: ?Object): node is (BinaryExpression | LogicalExpression); + declare export function isScopable(node: ?Object, opts?: ?Object): node is (BlockStatement | CatchClause | DoWhileStatement | ForInStatement | ForStatement | FunctionDeclaration | FunctionExpression | Program | ObjectMethod | SwitchStatement | WhileStatement | ArrowFunctionExpression | ClassExpression | ClassDeclaration | ForOfStatement | ClassMethod | ClassPrivateMethod | StaticBlock | TSModuleBlock); + declare export function isBlockParent(node: ?Object, opts?: ?Object): node is (BlockStatement | CatchClause | DoWhileStatement | ForInStatement | ForStatement | FunctionDeclaration | FunctionExpression | Program | ObjectMethod | SwitchStatement | WhileStatement | ArrowFunctionExpression | ForOfStatement | ClassMethod | ClassPrivateMethod | StaticBlock | TSModuleBlock); + declare export function isBlock(node: ?Object, opts?: ?Object): node is (BlockStatement | Program | TSModuleBlock); + declare export function isStatement(node: ?Object, opts?: ?Object): node is (BlockStatement | BreakStatement | ContinueStatement | DebuggerStatement | DoWhileStatement | EmptyStatement | ExpressionStatement | ForInStatement | ForStatement | FunctionDeclaration | IfStatement | LabeledStatement | ReturnStatement | SwitchStatement | ThrowStatement | TryStatement | VariableDeclaration | WhileStatement | WithStatement | ClassDeclaration | ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration | ForOfStatement | ImportDeclaration | DeclareClass | DeclareFunction | DeclareInterface | DeclareModule | DeclareModuleExports | DeclareTypeAlias | DeclareOpaqueType | DeclareVariable | DeclareExportDeclaration | DeclareExportAllDeclaration | InterfaceDeclaration | OpaqueType | TypeAlias | EnumDeclaration | TSDeclareFunction | TSInterfaceDeclaration | TSTypeAliasDeclaration | TSEnumDeclaration | TSModuleDeclaration | TSImportEqualsDeclaration | TSExportAssignment | TSNamespaceExportDeclaration); + declare export function isTerminatorless(node: ?Object, opts?: ?Object): node is (BreakStatement | ContinueStatement | ReturnStatement | ThrowStatement | YieldExpression | AwaitExpression); + declare export function isCompletionStatement(node: ?Object, opts?: ?Object): node is (BreakStatement | ContinueStatement | ReturnStatement | ThrowStatement); + declare export function isConditional(node: ?Object, opts?: ?Object): node is (ConditionalExpression | IfStatement); + declare export function isLoop(node: ?Object, opts?: ?Object): node is (DoWhileStatement | ForInStatement | ForStatement | WhileStatement | ForOfStatement); + declare export function isWhile(node: ?Object, opts?: ?Object): node is (DoWhileStatement | WhileStatement); + declare export function isExpressionWrapper(node: ?Object, opts?: ?Object): node is (ExpressionStatement | ParenthesizedExpression | TypeCastExpression); + declare export function isFor(node: ?Object, opts?: ?Object): node is (ForInStatement | ForStatement | ForOfStatement); + declare export function isForXStatement(node: ?Object, opts?: ?Object): node is (ForInStatement | ForOfStatement); + declare export function isFunction(node: ?Object, opts?: ?Object): node is (FunctionDeclaration | FunctionExpression | ObjectMethod | ArrowFunctionExpression | ClassMethod | ClassPrivateMethod); + declare export function isFunctionParent(node: ?Object, opts?: ?Object): node is (FunctionDeclaration | FunctionExpression | ObjectMethod | ArrowFunctionExpression | ClassMethod | ClassPrivateMethod | StaticBlock | TSModuleBlock); + declare export function isPureish(node: ?Object, opts?: ?Object): node is (FunctionDeclaration | FunctionExpression | StringLiteral | NumericLiteral | NullLiteral | BooleanLiteral | RegExpLiteral | ArrowFunctionExpression | BigIntLiteral | DecimalLiteral); + declare export function isDeclaration(node: ?Object, opts?: ?Object): node is (FunctionDeclaration | VariableDeclaration | ClassDeclaration | ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration | ImportDeclaration | DeclareClass | DeclareFunction | DeclareInterface | DeclareModule | DeclareModuleExports | DeclareTypeAlias | DeclareOpaqueType | DeclareVariable | DeclareExportDeclaration | DeclareExportAllDeclaration | InterfaceDeclaration | OpaqueType | TypeAlias | EnumDeclaration | TSDeclareFunction | TSInterfaceDeclaration | TSTypeAliasDeclaration | TSEnumDeclaration | TSModuleDeclaration); + declare export function isPatternLike(node: ?Object, opts?: ?Object): node is (Identifier | RestElement | AssignmentPattern | ArrayPattern | ObjectPattern | TSAsExpression | TSSatisfiesExpression | TSTypeAssertion | TSNonNullExpression); + declare export function isLVal(node: ?Object, opts?: ?Object): node is (Identifier | MemberExpression | RestElement | AssignmentPattern | ArrayPattern | ObjectPattern | TSParameterProperty | TSAsExpression | TSSatisfiesExpression | TSTypeAssertion | TSNonNullExpression); + declare export function isTSEntityName(node: ?Object, opts?: ?Object): node is (Identifier | TSQualifiedName); + declare export function isLiteral(node: ?Object, opts?: ?Object): node is (StringLiteral | NumericLiteral | NullLiteral | BooleanLiteral | RegExpLiteral | TemplateLiteral | BigIntLiteral | DecimalLiteral); + declare export function isImmutable(node: ?Object, opts?: ?Object): node is (StringLiteral | NumericLiteral | NullLiteral | BooleanLiteral | BigIntLiteral | JSXAttribute | JSXClosingElement | JSXElement | JSXExpressionContainer | JSXSpreadChild | JSXOpeningElement | JSXText | JSXFragment | JSXOpeningFragment | JSXClosingFragment | DecimalLiteral); + declare export function isUserWhitespacable(node: ?Object, opts?: ?Object): node is (ObjectMethod | ObjectProperty | ObjectTypeInternalSlot | ObjectTypeCallProperty | ObjectTypeIndexer | ObjectTypeProperty | ObjectTypeSpreadProperty); + declare export function isMethod(node: ?Object, opts?: ?Object): node is (ObjectMethod | ClassMethod | ClassPrivateMethod); + declare export function isObjectMember(node: ?Object, opts?: ?Object): node is (ObjectMethod | ObjectProperty); + declare export function isProperty(node: ?Object, opts?: ?Object): node is (ObjectProperty | ClassProperty | ClassAccessorProperty | ClassPrivateProperty); + declare export function isUnaryLike(node: ?Object, opts?: ?Object): node is (UnaryExpression | SpreadElement); + declare export function isPattern(node: ?Object, opts?: ?Object): node is (AssignmentPattern | ArrayPattern | ObjectPattern); + declare export function isClass(node: ?Object, opts?: ?Object): node is (ClassExpression | ClassDeclaration); + declare export function isModuleDeclaration(node: ?Object, opts?: ?Object): node is (ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration | ImportDeclaration); + declare export function isExportDeclaration(node: ?Object, opts?: ?Object): node is (ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration); + declare export function isModuleSpecifier(node: ?Object, opts?: ?Object): node is (ExportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | ImportSpecifier | ExportNamespaceSpecifier | ExportDefaultSpecifier); + declare export function isAccessor(node: ?Object, opts?: ?Object): node is (ClassAccessorProperty); + declare export function isPrivate(node: ?Object, opts?: ?Object): node is (ClassPrivateProperty | ClassPrivateMethod | PrivateName); + declare export function isFlow(node: ?Object, opts?: ?Object): node is (AnyTypeAnnotation | ArrayTypeAnnotation | BooleanTypeAnnotation | BooleanLiteralTypeAnnotation | NullLiteralTypeAnnotation | ClassImplements | DeclareClass | DeclareFunction | DeclareInterface | DeclareModule | DeclareModuleExports | DeclareTypeAlias | DeclareOpaqueType | DeclareVariable | DeclareExportDeclaration | DeclareExportAllDeclaration | DeclaredPredicate | ExistsTypeAnnotation | FunctionTypeAnnotation | FunctionTypeParam | GenericTypeAnnotation | InferredPredicate | InterfaceExtends | InterfaceDeclaration | InterfaceTypeAnnotation | IntersectionTypeAnnotation | MixedTypeAnnotation | EmptyTypeAnnotation | NullableTypeAnnotation | NumberLiteralTypeAnnotation | NumberTypeAnnotation | ObjectTypeAnnotation | ObjectTypeInternalSlot | ObjectTypeCallProperty | ObjectTypeIndexer | ObjectTypeProperty | ObjectTypeSpreadProperty | OpaqueType | QualifiedTypeIdentifier | StringLiteralTypeAnnotation | StringTypeAnnotation | SymbolTypeAnnotation | ThisTypeAnnotation | TupleTypeAnnotation | TypeofTypeAnnotation | TypeAlias | TypeAnnotation | TypeCastExpression | TypeParameter | TypeParameterDeclaration | TypeParameterInstantiation | UnionTypeAnnotation | Variance | VoidTypeAnnotation | EnumDeclaration | EnumBooleanBody | EnumNumberBody | EnumStringBody | EnumSymbolBody | EnumBooleanMember | EnumNumberMember | EnumStringMember | EnumDefaultedMember | IndexedAccessType | OptionalIndexedAccessType); + declare export function isFlowType(node: ?Object, opts?: ?Object): node is (AnyTypeAnnotation | ArrayTypeAnnotation | BooleanTypeAnnotation | BooleanLiteralTypeAnnotation | NullLiteralTypeAnnotation | ExistsTypeAnnotation | FunctionTypeAnnotation | GenericTypeAnnotation | InterfaceTypeAnnotation | IntersectionTypeAnnotation | MixedTypeAnnotation | EmptyTypeAnnotation | NullableTypeAnnotation | NumberLiteralTypeAnnotation | NumberTypeAnnotation | ObjectTypeAnnotation | StringLiteralTypeAnnotation | StringTypeAnnotation | SymbolTypeAnnotation | ThisTypeAnnotation | TupleTypeAnnotation | TypeofTypeAnnotation | UnionTypeAnnotation | VoidTypeAnnotation | IndexedAccessType | OptionalIndexedAccessType); + declare export function isFlowBaseAnnotation(node: ?Object, opts?: ?Object): node is (AnyTypeAnnotation | BooleanTypeAnnotation | NullLiteralTypeAnnotation | MixedTypeAnnotation | EmptyTypeAnnotation | NumberTypeAnnotation | StringTypeAnnotation | SymbolTypeAnnotation | ThisTypeAnnotation | VoidTypeAnnotation); + declare export function isFlowDeclaration(node: ?Object, opts?: ?Object): node is (DeclareClass | DeclareFunction | DeclareInterface | DeclareModule | DeclareModuleExports | DeclareTypeAlias | DeclareOpaqueType | DeclareVariable | DeclareExportDeclaration | DeclareExportAllDeclaration | InterfaceDeclaration | OpaqueType | TypeAlias); + declare export function isFlowPredicate(node: ?Object, opts?: ?Object): node is (DeclaredPredicate | InferredPredicate); + declare export function isEnumBody(node: ?Object, opts?: ?Object): node is (EnumBooleanBody | EnumNumberBody | EnumStringBody | EnumSymbolBody); + declare export function isEnumMember(node: ?Object, opts?: ?Object): node is (EnumBooleanMember | EnumNumberMember | EnumStringMember | EnumDefaultedMember); + declare export function isJSX(node: ?Object, opts?: ?Object): node is (JSXAttribute | JSXClosingElement | JSXElement | JSXEmptyExpression | JSXExpressionContainer | JSXSpreadChild | JSXIdentifier | JSXMemberExpression | JSXNamespacedName | JSXOpeningElement | JSXSpreadAttribute | JSXText | JSXFragment | JSXOpeningFragment | JSXClosingFragment); + declare export function isMiscellaneous(node: ?Object, opts?: ?Object): node is (Noop | Placeholder | V8IntrinsicIdentifier); + declare export function isTypeScript(node: ?Object, opts?: ?Object): node is (TSParameterProperty | TSDeclareFunction | TSDeclareMethod | TSQualifiedName | TSCallSignatureDeclaration | TSConstructSignatureDeclaration | TSPropertySignature | TSMethodSignature | TSIndexSignature | TSAnyKeyword | TSBooleanKeyword | TSBigIntKeyword | TSIntrinsicKeyword | TSNeverKeyword | TSNullKeyword | TSNumberKeyword | TSObjectKeyword | TSStringKeyword | TSSymbolKeyword | TSUndefinedKeyword | TSUnknownKeyword | TSVoidKeyword | TSThisType | TSFunctionType | TSConstructorType | TSTypeReference | TSTypePredicate | TSTypeQuery | TSTypeLiteral | TSArrayType | TSTupleType | TSOptionalType | TSRestType | TSNamedTupleMember | TSUnionType | TSIntersectionType | TSConditionalType | TSInferType | TSParenthesizedType | TSTypeOperator | TSIndexedAccessType | TSMappedType | TSLiteralType | TSExpressionWithTypeArguments | TSInterfaceDeclaration | TSInterfaceBody | TSTypeAliasDeclaration | TSInstantiationExpression | TSAsExpression | TSSatisfiesExpression | TSTypeAssertion | TSEnumDeclaration | TSEnumMember | TSModuleDeclaration | TSModuleBlock | TSImportType | TSImportEqualsDeclaration | TSExternalModuleReference | TSNonNullExpression | TSExportAssignment | TSNamespaceExportDeclaration | TSTypeAnnotation | TSTypeParameterInstantiation | TSTypeParameterDeclaration | TSTypeParameter); + declare export function isTSTypeElement(node: ?Object, opts?: ?Object): node is (TSCallSignatureDeclaration | TSConstructSignatureDeclaration | TSPropertySignature | TSMethodSignature | TSIndexSignature); + declare export function isTSType(node: ?Object, opts?: ?Object): node is (TSAnyKeyword | TSBooleanKeyword | TSBigIntKeyword | TSIntrinsicKeyword | TSNeverKeyword | TSNullKeyword | TSNumberKeyword | TSObjectKeyword | TSStringKeyword | TSSymbolKeyword | TSUndefinedKeyword | TSUnknownKeyword | TSVoidKeyword | TSThisType | TSFunctionType | TSConstructorType | TSTypeReference | TSTypePredicate | TSTypeQuery | TSTypeLiteral | TSArrayType | TSTupleType | TSOptionalType | TSRestType | TSUnionType | TSIntersectionType | TSConditionalType | TSInferType | TSParenthesizedType | TSTypeOperator | TSIndexedAccessType | TSMappedType | TSLiteralType | TSExpressionWithTypeArguments | TSImportType); + declare export function isTSBaseType(node: ?Object, opts?: ?Object): node is (TSAnyKeyword | TSBooleanKeyword | TSBigIntKeyword | TSIntrinsicKeyword | TSNeverKeyword | TSNullKeyword | TSNumberKeyword | TSObjectKeyword | TSStringKeyword | TSSymbolKeyword | TSUndefinedKeyword | TSUnknownKeyword | TSVoidKeyword | TSThisType | TSLiteralType); + declare export function isNumberLiteral(node: ?Object, opts?: ?Object): node is NumericLiteral; + declare export function isRegexLiteral(node: ?Object, opts?: ?Object): node is RegExpLiteral; + declare export function isRestProperty(node: ?Object, opts?: ?Object): node is RestElement; + declare export function isSpreadProperty(node: ?Object, opts?: ?Object): node is SpreadElement; declare export function createTypeAnnotationBasedOnTypeof(type: 'string' | 'number' | 'undefined' | 'boolean' | 'function' | 'object' | 'symbol'): BabelNodeTypeAnnotation declare export function createUnionTypeAnnotation(types: Array): BabelNodeUnionTypeAnnotation declare export function createFlowUnionType(types: Array): BabelNodeUnionTypeAnnotation @@ -3796,18 +3796,18 @@ declare module "@babel/types" { declare export function is(type: string, n: BabelNode, opts: Object): boolean; declare export function isBinding(node: BabelNode, parent: BabelNode, grandparent?: BabelNode): boolean declare export function isBlockScoped(node: BabelNode): boolean - declare export function isLet(node: BabelNode): boolean %checks (node.type === 'VariableDeclaration') + declare export function isLet(node: BabelNode): node is VariableDeclaration declare export function isNode(node: ?Object): boolean declare export function isNodesEquivalent(a: any, b: any): boolean declare export function isPlaceholderType(placeholderType: string, targetType: string): boolean declare export function isReferenced(node: BabelNode, parent: BabelNode, grandparent?: BabelNode): boolean - declare export function isScope(node: BabelNode, parent: BabelNode): boolean %checks (node.type === 'BlockStatement' || node.type === 'CatchClause' || node.type === 'DoWhileStatement' || node.type === 'ForInStatement' || node.type === 'ForStatement' || node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'Program' || node.type === 'ObjectMethod' || node.type === 'SwitchStatement' || node.type === 'WhileStatement' || node.type === 'ArrowFunctionExpression' || node.type === 'ClassExpression' || node.type === 'ClassDeclaration' || node.type === 'ForOfStatement' || node.type === 'ClassMethod' || node.type === 'ClassPrivateMethod' || node.type === 'TSModuleBlock') + declare export function isScope(node: BabelNode, parent: BabelNode): node is (BlockStatement | CatchClause | DoWhileStatement | ForInStatement | ForStatement | FunctionDeclaration | FunctionExpression | Program | ObjectMethod | SwitchStatement | WhileStatement | ArrowFunctionExpression | ClassExpression | ClassDeclaration | ForOfStatement | ClassMethod | ClassPrivateMethod | TSModuleBlock) declare export function isSpecifierDefault(specifier: BabelNodeModuleSpecifier): boolean declare export function isType(nodetype: ?string, targetType: string): boolean declare export function isValidES3Identifier(name: string): boolean declare export function isValidES3Identifier(name: string): boolean declare export function isValidIdentifier(name: string): boolean - declare export function isVar(node: BabelNode): boolean %checks (node.type === 'VariableDeclaration') + declare export function isVar(node: BabelNode): node is VariableDeclaration declare export function matchesPattern(node: ?BabelNode, match: string | Array, allowPartial?: boolean): boolean declare export function validate(n: BabelNode, key: string, value: mixed): void; declare export type Node = BabelNode; diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c49b765..d64cd4917707c1 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8838ba97ba0914..e6aba2515d5428 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/package.json b/package.json index d5b2ea0e01b9fc..f7fe82fd37d5ef 100644 --- a/package.json +++ b/package.json @@ -83,10 +83,10 @@ "eslint-plugin-react-native": "^4.0.0", "eslint-plugin-redundant-undefined": "^0.4.0", "eslint-plugin-relay": "^1.8.3", - "flow-api-translator": "0.17.1", - "flow-bin": "^0.222.0", + "flow-api-translator": "0.18.0", + "flow-bin": "^0.223.0", "glob": "^7.1.1", - "hermes-eslint": "0.17.1", + "hermes-eslint": "0.18.0", "inquirer": "^7.1.0", "jest": "^29.6.3", "jest-junit": "^10.0.0", @@ -98,7 +98,7 @@ "mock-fs": "^5.1.4", "nullthrows": "^1.1.1", "prettier": "2.8.8", - "prettier-plugin-hermes-parser": "0.17.1", + "prettier-plugin-hermes-parser": "0.18.0", "react": "18.2.0", "react-test-renderer": "18.2.0", "rimraf": "^3.0.2", diff --git a/packages/community-cli-plugin/src/utils/loadMetroConfig.js b/packages/community-cli-plugin/src/utils/loadMetroConfig.js index c8430c9b9e4686..44d0d275cb0e64 100644 --- a/packages/community-cli-plugin/src/utils/loadMetroConfig.js +++ b/packages/community-cli-plugin/src/utils/loadMetroConfig.js @@ -29,7 +29,10 @@ export type ConfigLoadingContext = $ReadOnly<{ /** * Get the config options to override based on RN CLI inputs. */ -function getOverrideConfig(ctx: ConfigLoadingContext): InputConfigT { +function getOverrideConfig( + ctx: ConfigLoadingContext, + config: ConfigT, +): InputConfigT { const outOfTreePlatforms = Object.keys(ctx.platforms).filter( platform => ctx.platforms[platform].npmPackageName, ); @@ -46,6 +49,7 @@ function getOverrideConfig(ctx: ConfigLoadingContext): InputConfigT { }, {}, ), + config.resolver?.resolveRequest, ); } @@ -79,8 +83,6 @@ export default async function loadMetroConfig( ctx: ConfigLoadingContext, options: YargArguments = {}, ): Promise { - const overrideConfig = getOverrideConfig(ctx); - const cwd = ctx.root; const projectConfig = await resolveConfig(options.config, cwd); @@ -105,11 +107,12 @@ This warning will be removed in future (https://github.com/facebook/metro/issues } } - return mergeConfig( - await loadConfig({ - cwd, - ...options, - }), - overrideConfig, - ); + const config = await loadConfig({ + cwd, + ...options, + }); + + const overrideConfig = getOverrideConfig(ctx, config); + + return mergeConfig(config, overrideConfig); } diff --git a/packages/community-cli-plugin/src/utils/metroPlatformResolver.js b/packages/community-cli-plugin/src/utils/metroPlatformResolver.js index e03264f0c6442e..134ce7d2dad3d4 100644 --- a/packages/community-cli-plugin/src/utils/metroPlatformResolver.js +++ b/packages/community-cli-plugin/src/utils/metroPlatformResolver.js @@ -25,9 +25,12 @@ import type {CustomResolver} from 'metro-resolver'; * macos: 'react-native-macos' * } */ -export function reactNativePlatformResolver(platformImplementations: { - [platform: string]: string, -}): CustomResolver { +export function reactNativePlatformResolver( + platformImplementations: { + [platform: string]: string, + }, + customResolver: ?CustomResolver, +): CustomResolver { return (context, moduleName, platform) => { let modifiedModuleName = moduleName; if (platform != null && platformImplementations[platform]) { @@ -39,6 +42,9 @@ export function reactNativePlatformResolver(platformImplementations: { }/${modifiedModuleName.slice('react-native/'.length)}`; } } + if (customResolver) { + return customResolver(context, modifiedModuleName, platform); + } return context.resolveRequest(context, modifiedModuleName, platform); }; } diff --git a/packages/react-native-babel-transformer/package.json b/packages/react-native-babel-transformer/package.json index 677d5c654d4c03..a835dc80a1bdef 100644 --- a/packages/react-native-babel-transformer/package.json +++ b/packages/react-native-babel-transformer/package.json @@ -17,7 +17,7 @@ "dependencies": { "@babel/core": "^7.20.0", "@react-native/babel-preset": "*", - "hermes-parser": "0.17.1", + "hermes-parser": "0.18.0", "nullthrows": "^1.1.1" }, "peerDependencies": { diff --git a/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleH-test.js.snap b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleH-test.js.snap index 344b22b8866d77..ca285481d2374c 100644 --- a/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleH-test.js.snap +++ b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleH-test.js.snap @@ -324,7 +324,7 @@ struct Bridging { #pragma mark - NativeEnumTurboModuleBaseStateType template -struct NativeEnumTurboModuleBaseStateType { +struct [[deprecated(\\"Use NativeEnumTurboModuleStateType instead.\\")]] NativeEnumTurboModuleBaseStateType { P0 state; bool operator==(const NativeEnumTurboModuleBaseStateType &other) const { return state == other.state; @@ -332,7 +332,7 @@ struct NativeEnumTurboModuleBaseStateType { }; template -struct NativeEnumTurboModuleBaseStateTypeBridging { +struct [[deprecated(\\"Use NativeEnumTurboModuleStateTypeBridging instead.\\")]] NativeEnumTurboModuleBaseStateTypeBridging { static NativeEnumTurboModuleBaseStateType fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -363,7 +363,7 @@ struct NativeEnumTurboModuleBaseStateTypeBridging { #pragma mark - NativeEnumTurboModuleBaseStateTypeWithEnums template -struct NativeEnumTurboModuleBaseStateTypeWithEnums { +struct [[deprecated(\\"Use NativeEnumTurboModuleStateTypeWithEnums instead.\\")]] NativeEnumTurboModuleBaseStateTypeWithEnums { P0 state; P1 regular; P2 str; @@ -375,7 +375,7 @@ struct NativeEnumTurboModuleBaseStateTypeWithEnums { }; template -struct NativeEnumTurboModuleBaseStateTypeWithEnumsBridging { +struct [[deprecated(\\"Use NativeEnumTurboModuleStateTypeWithEnumsBridging instead.\\")]] NativeEnumTurboModuleBaseStateTypeWithEnumsBridging { static NativeEnumTurboModuleBaseStateTypeWithEnums fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -425,6 +425,115 @@ struct NativeEnumTurboModuleBaseStateTypeWithEnumsBridging { } }; + +#pragma mark - NativeEnumTurboModuleStateType + +template +struct NativeEnumTurboModuleStateType { + P0 state; + bool operator==(const NativeEnumTurboModuleStateType &other) const { + return state == other.state; + } +}; + +template +struct NativeEnumTurboModuleStateTypeBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String stateToJs(jsi::Runtime &rt, decltype(types.state) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"state\\", bridging::toJs(rt, value.state, jsInvoker)); + return result; + } +}; + + + +#pragma mark - NativeEnumTurboModuleStateTypeWithEnums + +template +struct NativeEnumTurboModuleStateTypeWithEnums { + P0 state; + P1 regular; + P2 str; + P3 num; + P4 fraction; + bool operator==(const NativeEnumTurboModuleStateTypeWithEnums &other) const { + return state == other.state && regular == other.regular && str == other.str && num == other.num && fraction == other.fraction; + } +}; + +template +struct NativeEnumTurboModuleStateTypeWithEnumsBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"regular\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"str\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"num\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"fraction\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String stateToJs(jsi::Runtime &rt, decltype(types.state) value) { + return bridging::toJs(rt, value); + } + + static jsi::String regularToJs(jsi::Runtime &rt, decltype(types.regular) value) { + return bridging::toJs(rt, value); + } + + static jsi::String strToJs(jsi::Runtime &rt, decltype(types.str) value) { + return bridging::toJs(rt, value); + } + + static int numToJs(jsi::Runtime &rt, decltype(types.num) value) { + return bridging::toJs(rt, value); + } + + static double fractionToJs(jsi::Runtime &rt, decltype(types.fraction) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"state\\", bridging::toJs(rt, value.state, jsInvoker)); + result.setProperty(rt, \\"regular\\", bridging::toJs(rt, value.regular, jsInvoker)); + result.setProperty(rt, \\"str\\", bridging::toJs(rt, value.str, jsInvoker)); + result.setProperty(rt, \\"num\\", bridging::toJs(rt, value.num, jsInvoker)); + result.setProperty(rt, \\"fraction\\", bridging::toJs(rt, value.fraction, jsInvoker)); + return result; + } +}; + class JSI_EXPORT NativeEnumTurboModuleCxxSpecJSI : public TurboModule { protected: NativeEnumTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); @@ -794,7 +903,7 @@ private: #pragma mark - NativePartialAnnotationTurboModuleBaseSomeObj template -struct NativePartialAnnotationTurboModuleBaseSomeObj { +struct [[deprecated(\\"Use NativePartialAnnotationTurboModuleSomeObj instead.\\")]] NativePartialAnnotationTurboModuleBaseSomeObj { P0 a; P1 b; bool operator==(const NativePartialAnnotationTurboModuleBaseSomeObj &other) const { @@ -803,7 +912,7 @@ struct NativePartialAnnotationTurboModuleBaseSomeObj { }; template -struct NativePartialAnnotationTurboModuleBaseSomeObjBridging { +struct [[deprecated(\\"Use NativePartialAnnotationTurboModuleSomeObjBridging instead.\\")]] NativePartialAnnotationTurboModuleBaseSomeObjBridging { static NativePartialAnnotationTurboModuleBaseSomeObj fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -837,6 +946,55 @@ struct NativePartialAnnotationTurboModuleBaseSomeObjBridging { } }; + +#pragma mark - NativePartialAnnotationTurboModuleSomeObj + +template +struct NativePartialAnnotationTurboModuleSomeObj { + P0 a; + P1 b; + bool operator==(const NativePartialAnnotationTurboModuleSomeObj &other) const { + return a == other.a && b == other.b; + } +}; + +template +struct NativePartialAnnotationTurboModuleSomeObjBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"a\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"b\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String aToJs(jsi::Runtime &rt, decltype(types.a) value) { + return bridging::toJs(rt, value); + } + + static bool bToJs(jsi::Runtime &rt, decltype(types.b) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"a\\", bridging::toJs(rt, value.a, jsInvoker)); + if (value.b) { + result.setProperty(rt, \\"b\\", bridging::toJs(rt, value.b.value(), jsInvoker)); + } + return result; + } +}; + class JSI_EXPORT NativePartialAnnotationTurboModuleCxxSpecJSI : public TurboModule { protected: NativePartialAnnotationTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); @@ -969,7 +1127,7 @@ private: #pragma mark - SampleTurboModuleBaseAnimal template -struct SampleTurboModuleBaseAnimal { +struct [[deprecated(\\"Use SampleTurboModuleAnimal instead.\\")]] SampleTurboModuleBaseAnimal { P0 name; bool operator==(const SampleTurboModuleBaseAnimal &other) const { return name == other.name; @@ -977,7 +1135,7 @@ struct SampleTurboModuleBaseAnimal { }; template -struct SampleTurboModuleBaseAnimalBridging { +struct [[deprecated(\\"Use SampleTurboModuleAnimalBridging instead.\\")]] SampleTurboModuleBaseAnimalBridging { static SampleTurboModuleBaseAnimal fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -1003,6 +1161,46 @@ struct SampleTurboModuleBaseAnimalBridging { } }; + +#pragma mark - SampleTurboModuleAnimal + +template +struct SampleTurboModuleAnimal { + P0 name; + bool operator==(const SampleTurboModuleAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleAnimalBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); @@ -1161,7 +1359,7 @@ private: #pragma mark - SampleTurboModuleArraysBaseAnimal template -struct SampleTurboModuleArraysBaseAnimal { +struct [[deprecated(\\"Use SampleTurboModuleArraysAnimal instead.\\")]] SampleTurboModuleArraysBaseAnimal { P0 name; bool operator==(const SampleTurboModuleArraysBaseAnimal &other) const { return name == other.name; @@ -1169,7 +1367,7 @@ struct SampleTurboModuleArraysBaseAnimal { }; template -struct SampleTurboModuleArraysBaseAnimalBridging { +struct [[deprecated(\\"Use SampleTurboModuleArraysAnimalBridging instead.\\")]] SampleTurboModuleArraysBaseAnimalBridging { static SampleTurboModuleArraysBaseAnimal fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -1195,6 +1393,46 @@ struct SampleTurboModuleArraysBaseAnimalBridging { } }; + +#pragma mark - SampleTurboModuleArraysAnimal + +template +struct SampleTurboModuleArraysAnimal { + P0 name; + bool operator==(const SampleTurboModuleArraysAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleArraysAnimalBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleArraysCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleArraysCxxSpecJSI(std::shared_ptr jsInvoker); @@ -1353,7 +1591,7 @@ private: #pragma mark - SampleTurboModuleNullableBaseAnimal template -struct SampleTurboModuleNullableBaseAnimal { +struct [[deprecated(\\"Use SampleTurboModuleNullableAnimal instead.\\")]] SampleTurboModuleNullableBaseAnimal { P0 name; bool operator==(const SampleTurboModuleNullableBaseAnimal &other) const { return name == other.name; @@ -1361,7 +1599,7 @@ struct SampleTurboModuleNullableBaseAnimal { }; template -struct SampleTurboModuleNullableBaseAnimalBridging { +struct [[deprecated(\\"Use SampleTurboModuleNullableAnimalBridging instead.\\")]] SampleTurboModuleNullableBaseAnimalBridging { static SampleTurboModuleNullableBaseAnimal fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -1387,6 +1625,46 @@ struct SampleTurboModuleNullableBaseAnimalBridging { } }; + +#pragma mark - SampleTurboModuleNullableAnimal + +template +struct SampleTurboModuleNullableAnimal { + P0 name; + bool operator==(const SampleTurboModuleNullableAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleNullableAnimalBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static std::optional nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleNullableCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleNullableCxxSpecJSI(std::shared_ptr jsInvoker); @@ -1545,7 +1823,7 @@ private: #pragma mark - SampleTurboModuleNullableAndOptionalBaseAnimal template -struct SampleTurboModuleNullableAndOptionalBaseAnimal { +struct [[deprecated(\\"Use SampleTurboModuleNullableAndOptionalAnimal instead.\\")]] SampleTurboModuleNullableAndOptionalBaseAnimal { P0 name; bool operator==(const SampleTurboModuleNullableAndOptionalBaseAnimal &other) const { return name == other.name; @@ -1553,7 +1831,7 @@ struct SampleTurboModuleNullableAndOptionalBaseAnimal { }; template -struct SampleTurboModuleNullableAndOptionalBaseAnimalBridging { +struct [[deprecated(\\"Use SampleTurboModuleNullableAndOptionalAnimalBridging instead.\\")]] SampleTurboModuleNullableAndOptionalBaseAnimalBridging { static SampleTurboModuleNullableAndOptionalBaseAnimal fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -1581,6 +1859,48 @@ struct SampleTurboModuleNullableAndOptionalBaseAnimalBridging { } }; + +#pragma mark - SampleTurboModuleNullableAndOptionalAnimal + +template +struct SampleTurboModuleNullableAndOptionalAnimal { + P0 name; + bool operator==(const SampleTurboModuleNullableAndOptionalAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleNullableAndOptionalAnimalBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static std::optional nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.name) { + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name.value(), jsInvoker)); + } + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI(std::shared_ptr jsInvoker); @@ -1739,7 +2059,7 @@ private: #pragma mark - SampleTurboModuleOptionalBaseAnimal template -struct SampleTurboModuleOptionalBaseAnimal { +struct [[deprecated(\\"Use SampleTurboModuleOptionalAnimal instead.\\")]] SampleTurboModuleOptionalBaseAnimal { P0 name; bool operator==(const SampleTurboModuleOptionalBaseAnimal &other) const { return name == other.name; @@ -1747,7 +2067,7 @@ struct SampleTurboModuleOptionalBaseAnimal { }; template -struct SampleTurboModuleOptionalBaseAnimalBridging { +struct [[deprecated(\\"Use SampleTurboModuleOptionalAnimalBridging instead.\\")]] SampleTurboModuleOptionalBaseAnimalBridging { static SampleTurboModuleOptionalBaseAnimal fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -1775,6 +2095,48 @@ struct SampleTurboModuleOptionalBaseAnimalBridging { } }; + +#pragma mark - SampleTurboModuleOptionalAnimal + +template +struct SampleTurboModuleOptionalAnimal { + P0 name; + bool operator==(const SampleTurboModuleOptionalAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleOptionalAnimalBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.name) { + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name.value(), jsInvoker)); + } + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleOptionalCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleOptionalCxxSpecJSI(std::shared_ptr jsInvoker); @@ -2296,49 +2658,156 @@ struct Bridging { } } - static jsi::Value toJs(jsi::Runtime &rt, NativeEnumTurboModuleStatusFractionEnum value) { - if (value == NativeEnumTurboModuleStatusFractionEnum::Active) { - return bridging::toJs(rt, 0.2f); - } else if (value == NativeEnumTurboModuleStatusFractionEnum::Paused) { - return bridging::toJs(rt, 0.1f); - } else if (value == NativeEnumTurboModuleStatusFractionEnum::Off) { - return bridging::toJs(rt, 0f); - } else { - throw jsi::JSError(rt, \\"No appropriate enum member found for enum value\\"); - } + static jsi::Value toJs(jsi::Runtime &rt, NativeEnumTurboModuleStatusFractionEnum value) { + if (value == NativeEnumTurboModuleStatusFractionEnum::Active) { + return bridging::toJs(rt, 0.2f); + } else if (value == NativeEnumTurboModuleStatusFractionEnum::Paused) { + return bridging::toJs(rt, 0.1f); + } else if (value == NativeEnumTurboModuleStatusFractionEnum::Off) { + return bridging::toJs(rt, 0f); + } else { + throw jsi::JSError(rt, \\"No appropriate enum member found for enum value\\"); + } + } +}; + +#pragma mark - NativeEnumTurboModuleBaseStateType + +template +struct [[deprecated(\\"Use NativeEnumTurboModuleStateType instead.\\")]] NativeEnumTurboModuleBaseStateType { + P0 state; + bool operator==(const NativeEnumTurboModuleBaseStateType &other) const { + return state == other.state; + } +}; + +template +struct [[deprecated(\\"Use NativeEnumTurboModuleStateTypeBridging instead.\\")]] NativeEnumTurboModuleBaseStateTypeBridging { + static NativeEnumTurboModuleBaseStateType fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + NativeEnumTurboModuleBaseStateType result{ + bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String stateToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const NativeEnumTurboModuleBaseStateType &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"state\\", bridging::toJs(rt, value.state, jsInvoker)); + return result; + } +}; + + + +#pragma mark - NativeEnumTurboModuleBaseStateTypeWithEnums + +template +struct [[deprecated(\\"Use NativeEnumTurboModuleStateTypeWithEnums instead.\\")]] NativeEnumTurboModuleBaseStateTypeWithEnums { + P0 state; + P1 regular; + P2 str; + P3 num; + P4 fraction; + bool operator==(const NativeEnumTurboModuleBaseStateTypeWithEnums &other) const { + return state == other.state && regular == other.regular && str == other.str && num == other.num && fraction == other.fraction; + } +}; + +template +struct [[deprecated(\\"Use NativeEnumTurboModuleStateTypeWithEnumsBridging instead.\\")]] NativeEnumTurboModuleBaseStateTypeWithEnumsBridging { + static NativeEnumTurboModuleBaseStateTypeWithEnums fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + NativeEnumTurboModuleBaseStateTypeWithEnums result{ + bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"regular\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"str\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"num\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"fraction\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String stateToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } + + static jsi::String regularToJs(jsi::Runtime &rt, P1 value) { + return bridging::toJs(rt, value); + } + + static jsi::String strToJs(jsi::Runtime &rt, P2 value) { + return bridging::toJs(rt, value); + } + + static int numToJs(jsi::Runtime &rt, P3 value) { + return bridging::toJs(rt, value); + } + + static double fractionToJs(jsi::Runtime &rt, P4 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const NativeEnumTurboModuleBaseStateTypeWithEnums &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"state\\", bridging::toJs(rt, value.state, jsInvoker)); + result.setProperty(rt, \\"regular\\", bridging::toJs(rt, value.regular, jsInvoker)); + result.setProperty(rt, \\"str\\", bridging::toJs(rt, value.str, jsInvoker)); + result.setProperty(rt, \\"num\\", bridging::toJs(rt, value.num, jsInvoker)); + result.setProperty(rt, \\"fraction\\", bridging::toJs(rt, value.fraction, jsInvoker)); + return result; } }; - -#pragma mark - NativeEnumTurboModuleBaseStateType + + +#pragma mark - NativeEnumTurboModuleStateType template -struct NativeEnumTurboModuleBaseStateType { +struct NativeEnumTurboModuleStateType { P0 state; - bool operator==(const NativeEnumTurboModuleBaseStateType &other) const { + bool operator==(const NativeEnumTurboModuleStateType &other) const { return state == other.state; } }; -template -struct NativeEnumTurboModuleBaseStateTypeBridging { - static NativeEnumTurboModuleBaseStateType fromJs( +template +struct NativeEnumTurboModuleStateTypeBridging { + static T types; + + static T fromJs( jsi::Runtime &rt, const jsi::Object &value, const std::shared_ptr &jsInvoker) { - NativeEnumTurboModuleBaseStateType result{ - bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker)}; + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker)}; return result; } #ifdef DEBUG - static jsi::String stateToJs(jsi::Runtime &rt, P0 value) { + static jsi::String stateToJs(jsi::Runtime &rt, decltype(types.state) value) { return bridging::toJs(rt, value); } #endif static jsi::Object toJs( jsi::Runtime &rt, - const NativeEnumTurboModuleBaseStateType &value, + const T &value, const std::shared_ptr &jsInvoker) { auto result = facebook::jsi::Object(rt); result.setProperty(rt, \\"state\\", bridging::toJs(rt, value.state, jsInvoker)); @@ -2348,60 +2817,62 @@ struct NativeEnumTurboModuleBaseStateTypeBridging { -#pragma mark - NativeEnumTurboModuleBaseStateTypeWithEnums +#pragma mark - NativeEnumTurboModuleStateTypeWithEnums template -struct NativeEnumTurboModuleBaseStateTypeWithEnums { +struct NativeEnumTurboModuleStateTypeWithEnums { P0 state; P1 regular; P2 str; P3 num; P4 fraction; - bool operator==(const NativeEnumTurboModuleBaseStateTypeWithEnums &other) const { + bool operator==(const NativeEnumTurboModuleStateTypeWithEnums &other) const { return state == other.state && regular == other.regular && str == other.str && num == other.num && fraction == other.fraction; } }; -template -struct NativeEnumTurboModuleBaseStateTypeWithEnumsBridging { - static NativeEnumTurboModuleBaseStateTypeWithEnums fromJs( +template +struct NativeEnumTurboModuleStateTypeWithEnumsBridging { + static T types; + + static T fromJs( jsi::Runtime &rt, const jsi::Object &value, const std::shared_ptr &jsInvoker) { - NativeEnumTurboModuleBaseStateTypeWithEnums result{ - bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker), - bridging::fromJs(rt, value.getProperty(rt, \\"regular\\"), jsInvoker), - bridging::fromJs(rt, value.getProperty(rt, \\"str\\"), jsInvoker), - bridging::fromJs(rt, value.getProperty(rt, \\"num\\"), jsInvoker), - bridging::fromJs(rt, value.getProperty(rt, \\"fraction\\"), jsInvoker)}; + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"regular\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"str\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"num\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"fraction\\"), jsInvoker)}; return result; } #ifdef DEBUG - static jsi::String stateToJs(jsi::Runtime &rt, P0 value) { + static jsi::String stateToJs(jsi::Runtime &rt, decltype(types.state) value) { return bridging::toJs(rt, value); } - static jsi::String regularToJs(jsi::Runtime &rt, P1 value) { + static jsi::String regularToJs(jsi::Runtime &rt, decltype(types.regular) value) { return bridging::toJs(rt, value); } - static jsi::String strToJs(jsi::Runtime &rt, P2 value) { + static jsi::String strToJs(jsi::Runtime &rt, decltype(types.str) value) { return bridging::toJs(rt, value); } - static int numToJs(jsi::Runtime &rt, P3 value) { + static int numToJs(jsi::Runtime &rt, decltype(types.num) value) { return bridging::toJs(rt, value); } - static double fractionToJs(jsi::Runtime &rt, P4 value) { + static double fractionToJs(jsi::Runtime &rt, decltype(types.fraction) value) { return bridging::toJs(rt, value); } #endif static jsi::Object toJs( jsi::Runtime &rt, - const NativeEnumTurboModuleBaseStateTypeWithEnums &value, + const T &value, const std::shared_ptr &jsInvoker) { auto result = facebook::jsi::Object(rt); result.setProperty(rt, \\"state\\", bridging::toJs(rt, value.state, jsInvoker)); @@ -2782,7 +3253,7 @@ private: #pragma mark - NativePartialAnnotationTurboModuleBaseSomeObj template -struct NativePartialAnnotationTurboModuleBaseSomeObj { +struct [[deprecated(\\"Use NativePartialAnnotationTurboModuleSomeObj instead.\\")]] NativePartialAnnotationTurboModuleBaseSomeObj { P0 a; P1 b; bool operator==(const NativePartialAnnotationTurboModuleBaseSomeObj &other) const { @@ -2791,7 +3262,7 @@ struct NativePartialAnnotationTurboModuleBaseSomeObj { }; template -struct NativePartialAnnotationTurboModuleBaseSomeObjBridging { +struct [[deprecated(\\"Use NativePartialAnnotationTurboModuleSomeObjBridging instead.\\")]] NativePartialAnnotationTurboModuleBaseSomeObjBridging { static NativePartialAnnotationTurboModuleBaseSomeObj fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -2825,6 +3296,55 @@ struct NativePartialAnnotationTurboModuleBaseSomeObjBridging { } }; + +#pragma mark - NativePartialAnnotationTurboModuleSomeObj + +template +struct NativePartialAnnotationTurboModuleSomeObj { + P0 a; + P1 b; + bool operator==(const NativePartialAnnotationTurboModuleSomeObj &other) const { + return a == other.a && b == other.b; + } +}; + +template +struct NativePartialAnnotationTurboModuleSomeObjBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"a\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"b\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String aToJs(jsi::Runtime &rt, decltype(types.a) value) { + return bridging::toJs(rt, value); + } + + static bool bToJs(jsi::Runtime &rt, decltype(types.b) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"a\\", bridging::toJs(rt, value.a, jsInvoker)); + if (value.b) { + result.setProperty(rt, \\"b\\", bridging::toJs(rt, value.b.value(), jsInvoker)); + } + return result; + } +}; + class JSI_EXPORT NativePartialAnnotationTurboModuleCxxSpecJSI : public TurboModule { protected: NativePartialAnnotationTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); @@ -2957,7 +3477,7 @@ private: #pragma mark - SampleTurboModuleBaseAnimal template -struct SampleTurboModuleBaseAnimal { +struct [[deprecated(\\"Use SampleTurboModuleAnimal instead.\\")]] SampleTurboModuleBaseAnimal { P0 name; bool operator==(const SampleTurboModuleBaseAnimal &other) const { return name == other.name; @@ -2965,7 +3485,7 @@ struct SampleTurboModuleBaseAnimal { }; template -struct SampleTurboModuleBaseAnimalBridging { +struct [[deprecated(\\"Use SampleTurboModuleAnimalBridging instead.\\")]] SampleTurboModuleBaseAnimalBridging { static SampleTurboModuleBaseAnimal fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -2991,6 +3511,46 @@ struct SampleTurboModuleBaseAnimalBridging { } }; + +#pragma mark - SampleTurboModuleAnimal + +template +struct SampleTurboModuleAnimal { + P0 name; + bool operator==(const SampleTurboModuleAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleAnimalBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); @@ -3149,7 +3709,7 @@ private: #pragma mark - SampleTurboModuleArraysBaseAnimal template -struct SampleTurboModuleArraysBaseAnimal { +struct [[deprecated(\\"Use SampleTurboModuleArraysAnimal instead.\\")]] SampleTurboModuleArraysBaseAnimal { P0 name; bool operator==(const SampleTurboModuleArraysBaseAnimal &other) const { return name == other.name; @@ -3157,7 +3717,7 @@ struct SampleTurboModuleArraysBaseAnimal { }; template -struct SampleTurboModuleArraysBaseAnimalBridging { +struct [[deprecated(\\"Use SampleTurboModuleArraysAnimalBridging instead.\\")]] SampleTurboModuleArraysBaseAnimalBridging { static SampleTurboModuleArraysBaseAnimal fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -3183,6 +3743,46 @@ struct SampleTurboModuleArraysBaseAnimalBridging { } }; + +#pragma mark - SampleTurboModuleArraysAnimal + +template +struct SampleTurboModuleArraysAnimal { + P0 name; + bool operator==(const SampleTurboModuleArraysAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleArraysAnimalBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleArraysCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleArraysCxxSpecJSI(std::shared_ptr jsInvoker); @@ -3341,7 +3941,7 @@ private: #pragma mark - SampleTurboModuleNullableBaseAnimal template -struct SampleTurboModuleNullableBaseAnimal { +struct [[deprecated(\\"Use SampleTurboModuleNullableAnimal instead.\\")]] SampleTurboModuleNullableBaseAnimal { P0 name; bool operator==(const SampleTurboModuleNullableBaseAnimal &other) const { return name == other.name; @@ -3349,7 +3949,7 @@ struct SampleTurboModuleNullableBaseAnimal { }; template -struct SampleTurboModuleNullableBaseAnimalBridging { +struct [[deprecated(\\"Use SampleTurboModuleNullableAnimalBridging instead.\\")]] SampleTurboModuleNullableBaseAnimalBridging { static SampleTurboModuleNullableBaseAnimal fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -3375,6 +3975,46 @@ struct SampleTurboModuleNullableBaseAnimalBridging { } }; + +#pragma mark - SampleTurboModuleNullableAnimal + +template +struct SampleTurboModuleNullableAnimal { + P0 name; + bool operator==(const SampleTurboModuleNullableAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleNullableAnimalBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static std::optional nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleNullableCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleNullableCxxSpecJSI(std::shared_ptr jsInvoker); @@ -3533,7 +4173,7 @@ private: #pragma mark - SampleTurboModuleNullableAndOptionalBaseAnimal template -struct SampleTurboModuleNullableAndOptionalBaseAnimal { +struct [[deprecated(\\"Use SampleTurboModuleNullableAndOptionalAnimal instead.\\")]] SampleTurboModuleNullableAndOptionalBaseAnimal { P0 name; bool operator==(const SampleTurboModuleNullableAndOptionalBaseAnimal &other) const { return name == other.name; @@ -3541,7 +4181,7 @@ struct SampleTurboModuleNullableAndOptionalBaseAnimal { }; template -struct SampleTurboModuleNullableAndOptionalBaseAnimalBridging { +struct [[deprecated(\\"Use SampleTurboModuleNullableAndOptionalAnimalBridging instead.\\")]] SampleTurboModuleNullableAndOptionalBaseAnimalBridging { static SampleTurboModuleNullableAndOptionalBaseAnimal fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -3569,6 +4209,48 @@ struct SampleTurboModuleNullableAndOptionalBaseAnimalBridging { } }; + +#pragma mark - SampleTurboModuleNullableAndOptionalAnimal + +template +struct SampleTurboModuleNullableAndOptionalAnimal { + P0 name; + bool operator==(const SampleTurboModuleNullableAndOptionalAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleNullableAndOptionalAnimalBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static std::optional nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.name) { + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name.value(), jsInvoker)); + } + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI(std::shared_ptr jsInvoker); @@ -3727,7 +4409,7 @@ private: #pragma mark - SampleTurboModuleOptionalBaseAnimal template -struct SampleTurboModuleOptionalBaseAnimal { +struct [[deprecated(\\"Use SampleTurboModuleOptionalAnimal instead.\\")]] SampleTurboModuleOptionalBaseAnimal { P0 name; bool operator==(const SampleTurboModuleOptionalBaseAnimal &other) const { return name == other.name; @@ -3735,7 +4417,7 @@ struct SampleTurboModuleOptionalBaseAnimal { }; template -struct SampleTurboModuleOptionalBaseAnimalBridging { +struct [[deprecated(\\"Use SampleTurboModuleOptionalAnimalBridging instead.\\")]] SampleTurboModuleOptionalBaseAnimalBridging { static SampleTurboModuleOptionalBaseAnimal fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -3763,6 +4445,48 @@ struct SampleTurboModuleOptionalBaseAnimalBridging { } }; + +#pragma mark - SampleTurboModuleOptionalAnimal + +template +struct SampleTurboModuleOptionalAnimal { + P0 name; + bool operator==(const SampleTurboModuleOptionalAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleOptionalAnimalBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.name) { + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name.value(), jsInvoker)); + } + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleOptionalCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleOptionalCxxSpecJSI(std::shared_ptr jsInvoker); diff --git a/packages/react-native-codegen/package.json b/packages/react-native-codegen/package.json index 19e6afe09e9886..bc53457e773391 100644 --- a/packages/react-native-codegen/package.json +++ b/packages/react-native-codegen/package.json @@ -31,7 +31,7 @@ "dependencies": { "@babel/parser": "^7.20.0", "glob": "^7.1.1", - "hermes-parser": "0.17.1", + "hermes-parser": "0.18.0", "invariant": "^2.2.4", "jscodeshift": "^0.14.0", "mkdirp": "^0.5.1", @@ -49,7 +49,7 @@ "@babel/plugin-transform-flow-strip-types": "^7.20.0", "@babel/preset-env": "^7.20.0", "chalk": "^4.0.0", - "hermes-estree": "0.17.1", + "hermes-estree": "0.18.0", "micromatch": "^4.0.4", "prettier": "2.8.8", "rimraf": "^3.0.2" diff --git a/packages/react-native-codegen/src/cli/combine/__tests__/combine-utils-test.js b/packages/react-native-codegen/src/cli/combine/__tests__/combine-utils-test.js index 08b75933d863b1..117dcb0f596772 100644 --- a/packages/react-native-codegen/src/cli/combine/__tests__/combine-utils-test.js +++ b/packages/react-native-codegen/src/cli/combine/__tests__/combine-utils-test.js @@ -103,9 +103,19 @@ describe('filterJSFile', () => { }); describe('When the file is NativeSampleTurboModule', () => { - it('returns false', () => { + it('returns true', () => { const file = 'NativeSampleTurboModule.js'; const result = filterJSFile(file); + expect(result).toBeTruthy(); + }); + + it('returns false, when excluded', () => { + const file = 'NativeSampleTurboModule.js'; + const result = filterJSFile( + file, + null, + new RegExp('NativeSampleTurboModule'), + ); expect(result).toBeFalsy(); }); }); diff --git a/packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js b/packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js index b67a92a1a42261..790b47d4fcf966 100644 --- a/packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js +++ b/packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js @@ -11,45 +11,13 @@ 'use strict'; -const combine = require('./combine-js-to-schema'); -const {filterJSFile, parseArgs} = require('./combine-utils'); -const fs = require('fs'); -const glob = require('glob'); -const path = require('path'); +const { + combineSchemasInFileListAndWriteToFile, +} = require('./combine-js-to-schema'); +const {parseArgs} = require('./combine-utils'); -const {platform, outfile, fileList} = parseArgs(process.argv); +const parsedArgs = parseArgs(process.argv); -const allFiles = []; -fileList.forEach(file => { - if (fs.lstatSync(file).isDirectory()) { - const filePattern = path.sep === '\\' ? file.replace(/\\/g, '/') : file; - const dirFiles = glob - .sync(`${filePattern}/**/*.{js,ts,tsx}`, { - nodir: true, - // TODO: This will remove the need of slash substitution above for Windows, - // but it requires glob@v9+; with the package currenlty relying on - // glob@7.1.1; and flow-typed repo not having definitions for glob@9+. - // windowsPathsNoEscape: true, - }) - .filter(element => filterJSFile(element, platform)); - allFiles.push(...dirFiles); - } else if (filterJSFile(file)) { - allFiles.push(file); - } -}); +const {platform, outfile, fileList, exclude} = parsedArgs; -const combined = combine(allFiles); - -// Warn users if there is no modules to process -if (Object.keys(combined.modules).length === 0) { - console.error( - 'No modules to process in combine-js-to-schema-cli. If this is unexpected, please check if you set up your NativeComponent correctly. See combine-js-to-schema.js for how codegen finds modules.', - ); -} -const formattedSchema = JSON.stringify(combined, null, 2); - -if (outfile != null) { - fs.writeFileSync(outfile, formattedSchema); -} else { - console.log(formattedSchema); -} +combineSchemasInFileListAndWriteToFile(fileList, platform, outfile, exclude); diff --git a/packages/react-native-codegen/src/cli/combine/combine-js-to-schema.js b/packages/react-native-codegen/src/cli/combine/combine-js-to-schema.js index a2dcef55c43dab..108edf99d81319 100644 --- a/packages/react-native-codegen/src/cli/combine/combine-js-to-schema.js +++ b/packages/react-native-codegen/src/cli/combine/combine-js-to-schema.js @@ -13,7 +13,9 @@ import type {SchemaType} from '../../CodegenSchema.js'; const {FlowParser} = require('../../parsers/flow/parser'); const {TypeScriptParser} = require('../../parsers/typescript/parser'); +const {filterJSFile} = require('./combine-utils'); const fs = require('fs'); +const glob = require('glob'); const path = require('path'); const flowParser = new FlowParser(); @@ -46,4 +48,60 @@ function combineSchemas(files: Array): SchemaType { ); } -module.exports = combineSchemas; +function expandDirectoriesIntoFiles( + fileList: Array, + platform: ?string, + exclude: ?RegExp, +): Array { + return fileList + .flatMap(file => { + if (!fs.lstatSync(file).isDirectory()) { + return [file]; + } + const filePattern = path.sep === '\\' ? file.replace(/\\/g, '/') : file; + return glob.sync(`${filePattern}/**/*.{js,ts,tsx}`, { + nodir: true, + // TODO: This will remove the need of slash substitution above for Windows, + // but it requires glob@v9+; with the package currenlty relying on + // glob@7.1.1; and flow-typed repo not having definitions for glob@9+. + // windowsPathsNoEscape: true, + }); + }) + .filter(element => filterJSFile(element, platform, exclude)); +} + +function combineSchemasInFileList( + fileList: Array, + platform: ?string, + exclude: ?RegExp, +): SchemaType { + const expandedFileList = expandDirectoriesIntoFiles( + fileList, + platform, + exclude, + ); + const combined = combineSchemas(expandedFileList); + if (Object.keys(combined.modules).length === 0) { + console.error( + 'No modules to process in combine-js-to-schema-cli. If this is unexpected, please check if you set up your NativeComponent correctly. See combine-js-to-schema.js for how codegen finds modules.', + ); + } + return combined; +} + +function combineSchemasInFileListAndWriteToFile( + fileList: Array, + platform: ?string, + outfile: string, + exclude: ?RegExp, +): void { + const combined = combineSchemasInFileList(fileList, platform, exclude); + const formattedSchema = JSON.stringify(combined, null, 2); + fs.writeFileSync(outfile, formattedSchema); +} + +module.exports = { + combineSchemas, + combineSchemasInFileList, + combineSchemasInFileListAndWriteToFile, +}; diff --git a/packages/react-native-codegen/src/cli/combine/combine-schemas-cli.js b/packages/react-native-codegen/src/cli/combine/combine-schemas-cli.js new file mode 100644 index 00000000000000..d8425e10ef018a --- /dev/null +++ b/packages/react-native-codegen/src/cli/combine/combine-schemas-cli.js @@ -0,0 +1,85 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type { + ComponentSchema, + NativeModuleSchema, + SchemaType, +} from '../../CodegenSchema.js'; + +const assert = require('assert'); +const fs = require('fs'); +const util = require('util'); + +const {values: args} = util.parseArgs({ + options: { + platform: { + type: 'string', + }, + output: { + type: 'string', + }, + ['schema-query']: { + type: 'string', + }, + }, +}); +if (!['iOS', 'android'].includes(args.platform)) { + throw new Error(`Invalid platform ${args.platform}`); +} +const platform = args.platform; +const output = args.output; +const schemaQuery: string = args['schema-query']; + +if (!schemaQuery.startsWith('@')) { + throw new Error( + "The argument provided to --schema-query must be a filename that starts with '@'.", + ); +} + +const schemaQueryOutputFile = schemaQuery.replace(/^@/, ''); +const schemaQueryOutput = fs.readFileSync(schemaQueryOutputFile, 'utf8'); + +const schemaFiles = schemaQueryOutput.split(' '); +const modules: { + [hasteModuleName: string]: NativeModuleSchema | ComponentSchema, +} = {}; +const specNameToFile: {[hasteModuleName: string]: string} = {}; + +for (const file of schemaFiles) { + const schema: SchemaType = JSON.parse(fs.readFileSync(file, 'utf8')); + + if (schema.modules) { + for (const specName in schema.modules) { + const module = schema.modules[specName]; + if (modules[specName]) { + assert.deepEqual( + module, + modules[specName], + `App contained two specs with the same file name '${specName}'. Schemas: ${specNameToFile[specName]}, ${file}. Please rename one of the specs.`, + ); + } + + if ( + module.excludedPlatforms && + module.excludedPlatforms.indexOf(platform) >= 0 + ) { + continue; + } + + modules[specName] = module; + specNameToFile[specName] = file; + } + } +} + +fs.writeFileSync(output, JSON.stringify({modules}, null, 2)); diff --git a/packages/react-native-codegen/src/cli/combine/combine-utils.js b/packages/react-native-codegen/src/cli/combine/combine-utils.js index 5dad6e041b6b99..a54a17ce26b504 100644 --- a/packages/react-native-codegen/src/cli/combine/combine-utils.js +++ b/packages/react-native-codegen/src/cli/combine/combine-utils.js @@ -12,26 +12,41 @@ 'use strict'; const path = require('path'); +const util = require('util'); function parseArgs(args: string[]): { platform: ?string, outfile: string, fileList: string[], + exclude: ?RegExp, } { - if (args.length > 2 && ['-p', '--platform'].indexOf(args[2]) >= 0) { - const [outfile, ...fileList] = args.slice(4); - return { - platform: args[3], - outfile, - fileList, - }; - } + const parsedArgs = util.parseArgs({ + args: args.slice(2), + options: { + platform: { + short: 'p', + type: 'string', + }, + exclude: { + short: 'e', + type: 'string', + }, + }, + allowPositionals: true, + }); + + const { + values: {platform, exclude}, + positionals: files, + } = parsedArgs; + + const [outfile, ...fileList] = files; - const [outfile, ...fileList] = args.slice(2); return { - platform: null, + platform: platform ?? null, outfile, fileList, + exclude: exclude != null && exclude !== '' ? new RegExp(exclude) : null, }; } @@ -43,19 +58,21 @@ function parseArgs(args: string[]): { * Returns: `true` if the file can be used to generate some code; `false` otherwise * */ -function filterJSFile(file: string, currentPlatform: ?string): boolean { +function filterJSFile( + file: string, + currentPlatform: ?string, + excludeRegExp: ?RegExp, +): boolean { const isSpecFile = /^(Native.+|.+NativeComponent)/.test(path.basename(file)); const isNotNativeUIManager = !file.endsWith('NativeUIManager.js'); - const isNotNativeSampleTurboModule = !file.endsWith( - 'NativeSampleTurboModule.js', - ); const isNotTest = !file.includes('__tests'); + const isNotExcluded = excludeRegExp == null || !excludeRegExp.test(file); const isNotTSTypeDefinition = !file.endsWith('.d.ts'); const isValidCandidate = isSpecFile && isNotNativeUIManager && - isNotNativeSampleTurboModule && + isNotExcluded && isNotTest && isNotTSTypeDefinition; diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js index 6dd3289216aadc..31b29998105089 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js @@ -232,33 +232,36 @@ function createStructsString( enumMap, ); - return Object.keys(aliasMap) - .map(alias => { - const value = aliasMap[alias]; - if (value.properties.length === 0) { - return ''; - } - const structName = `${moduleName}Base${alias}`; - const templateParameterWithTypename = value.properties - .map((v, i) => `typename P${i}`) - .join(', '); - const templateParameter = value.properties - .map((v, i) => 'P' + i) - .join(', '); - const debugParameterConversion = value.properties - .map( - (v, i) => ` static ${getCppType(v)} ${ - v.name - }ToJs(jsi::Runtime &rt, P${i} value) { + // TODO: T171006733 [Begin] Remove deprecated Cxx TMs structs after a new release. + return ( + Object.keys(aliasMap) + .map(alias => { + const value = aliasMap[alias]; + if (value.properties.length === 0) { + return ''; + } + const structName = `${moduleName}Base${alias}`; + const structNameNew = `${moduleName}${alias}`; + const templateParameterWithTypename = value.properties + .map((v, i) => `typename P${i}`) + .join(', '); + const templateParameter = value.properties + .map((v, i) => 'P' + i) + .join(', '); + const debugParameterConversion = value.properties + .map( + (v, i) => ` static ${getCppType(v)} ${ + v.name + }ToJs(jsi::Runtime &rt, P${i} value) { return bridging::toJs(rt, value); }`, - ) - .join('\n\n'); - return ` + ) + .join('\n\n'); + return ` #pragma mark - ${structName} template <${templateParameterWithTypename}> -struct ${structName} { +struct [[deprecated("Use ${structNameNew} instead.")]] ${structName} { ${value.properties.map((v, i) => ' P' + i + ' ' + v.name).join(';\n')}; bool operator==(const ${structName} &other) const { return ${value.properties @@ -268,7 +271,7 @@ ${value.properties.map((v, i) => ' P' + i + ' ' + v.name).join(';\n')}; }; template <${templateParameterWithTypename}> -struct ${structName}Bridging { +struct [[deprecated("Use ${structNameNew}Bridging instead.")]] ${structName}Bridging { static ${structName}<${templateParameter}> fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -308,8 +311,87 @@ ${value.properties }; `; - }) - .join('\n'); + }) + .join('\n') + + // TODO: T171006733 [End] Remove deprecated Cxx TMs structs after a new release. + Object.keys(aliasMap) + .map(alias => { + const value = aliasMap[alias]; + if (value.properties.length === 0) { + return ''; + } + const structName = `${moduleName}${alias}`; + const templateParameterWithTypename = value.properties + .map((v, i) => `typename P${i}`) + .join(', '); + const debugParameterConversion = value.properties + .map( + (v, i) => ` static ${getCppType(v)} ${ + v.name + }ToJs(jsi::Runtime &rt, decltype(types.${v.name}) value) { + return bridging::toJs(rt, value); + }`, + ) + .join('\n\n'); + return ` +#pragma mark - ${structName} + +template <${templateParameterWithTypename}> +struct ${structName} { +${value.properties.map((v, i) => ' P' + i + ' ' + v.name).join(';\n')}; + bool operator==(const ${structName} &other) const { + return ${value.properties + .map(v => `${v.name} == other.${v.name}`) + .join(' && ')}; + } +}; + +template +struct ${structName}Bridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ +${value.properties + .map( + (v, i) => + ` bridging::fromJs(rt, value.getProperty(rt, "${v.name}"), jsInvoker)`, + ) + .join(',\n')}}; + return result; + } + +#ifdef DEBUG +${debugParameterConversion} +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); +${value.properties + .map((v, i) => { + if (v.optional) { + return ` if (value.${v.name}) { + result.setProperty(rt, "${v.name}", bridging::toJs(rt, value.${v.name}.value(), jsInvoker)); + }`; + } else { + return ` result.setProperty(rt, "${v.name}", bridging::toJs(rt, value.${v.name}, jsInvoker));`; + } + }) + .join('\n')} + return result; + } +}; + +`; + }) + .join('\n') + ); } type NativeEnumMemberValueType = 'std::string' | 'int32_t' | 'float'; diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap index 75e2dd9187d176..aa012fe2c151e3 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap @@ -300,7 +300,7 @@ struct Bridging { #pragma mark - SampleTurboModuleCxxBaseObjectAlias template -struct SampleTurboModuleCxxBaseObjectAlias { +struct [[deprecated(\\"Use SampleTurboModuleCxxObjectAlias instead.\\")]] SampleTurboModuleCxxBaseObjectAlias { P0 x; bool operator==(const SampleTurboModuleCxxBaseObjectAlias &other) const { return x == other.x; @@ -308,7 +308,7 @@ struct SampleTurboModuleCxxBaseObjectAlias { }; template -struct SampleTurboModuleCxxBaseObjectAliasBridging { +struct [[deprecated(\\"Use SampleTurboModuleCxxObjectAliasBridging instead.\\")]] SampleTurboModuleCxxBaseObjectAliasBridging { static SampleTurboModuleCxxBaseObjectAlias fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -334,6 +334,46 @@ struct SampleTurboModuleCxxBaseObjectAliasBridging { } }; + +#pragma mark - SampleTurboModuleCxxObjectAlias + +template +struct SampleTurboModuleCxxObjectAlias { + P0 x; + bool operator==(const SampleTurboModuleCxxObjectAlias &other) const { + return x == other.x; + } +}; + +template +struct SampleTurboModuleCxxObjectAliasBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"x\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static double xToJs(jsi::Runtime &rt, decltype(types.x) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"x\\", bridging::toJs(rt, value.x, jsInvoker)); + return result; + } +}; + class JSI_EXPORT NativeSampleTurboModuleCxxSpecJSI : public TurboModule { protected: NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); @@ -509,7 +549,7 @@ namespace react { #pragma mark - AliasTurboModuleBaseOptions template -struct AliasTurboModuleBaseOptions { +struct [[deprecated(\\"Use AliasTurboModuleOptions instead.\\")]] AliasTurboModuleBaseOptions { P0 offset; P1 size; P2 displaySize; @@ -521,7 +561,7 @@ struct AliasTurboModuleBaseOptions { }; template -struct AliasTurboModuleBaseOptionsBridging { +struct [[deprecated(\\"Use AliasTurboModuleOptionsBridging instead.\\")]] AliasTurboModuleBaseOptionsBridging { static AliasTurboModuleBaseOptions fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -577,6 +617,80 @@ struct AliasTurboModuleBaseOptionsBridging { } }; + +#pragma mark - AliasTurboModuleOptions + +template +struct AliasTurboModuleOptions { + P0 offset; + P1 size; + P2 displaySize; + P3 resizeMode; + P4 allowExternalStorage; + bool operator==(const AliasTurboModuleOptions &other) const { + return offset == other.offset && size == other.size && displaySize == other.displaySize && resizeMode == other.resizeMode && allowExternalStorage == other.allowExternalStorage; + } +}; + +template +struct AliasTurboModuleOptionsBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"offset\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"size\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"displaySize\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"resizeMode\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"allowExternalStorage\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::Object offsetToJs(jsi::Runtime &rt, decltype(types.offset) value) { + return bridging::toJs(rt, value); + } + + static jsi::Object sizeToJs(jsi::Runtime &rt, decltype(types.size) value) { + return bridging::toJs(rt, value); + } + + static jsi::Object displaySizeToJs(jsi::Runtime &rt, decltype(types.displaySize) value) { + return bridging::toJs(rt, value); + } + + static jsi::String resizeModeToJs(jsi::Runtime &rt, decltype(types.resizeMode) value) { + return bridging::toJs(rt, value); + } + + static bool allowExternalStorageToJs(jsi::Runtime &rt, decltype(types.allowExternalStorage) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"offset\\", bridging::toJs(rt, value.offset, jsInvoker)); + result.setProperty(rt, \\"size\\", bridging::toJs(rt, value.size, jsInvoker)); + if (value.displaySize) { + result.setProperty(rt, \\"displaySize\\", bridging::toJs(rt, value.displaySize.value(), jsInvoker)); + } + if (value.resizeMode) { + result.setProperty(rt, \\"resizeMode\\", bridging::toJs(rt, value.resizeMode.value(), jsInvoker)); + } + if (value.allowExternalStorage) { + result.setProperty(rt, \\"allowExternalStorage\\", bridging::toJs(rt, value.allowExternalStorage.value(), jsInvoker)); + } + return result; + } +}; + class JSI_EXPORT AliasTurboModuleCxxSpecJSI : public TurboModule { protected: AliasTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); @@ -661,7 +775,7 @@ namespace react { #pragma mark - CameraRollManagerBasePhotoIdentifierImage template -struct CameraRollManagerBasePhotoIdentifierImage { +struct [[deprecated(\\"Use CameraRollManagerPhotoIdentifierImage instead.\\")]] CameraRollManagerBasePhotoIdentifierImage { P0 uri; P1 playableDuration; P2 width; @@ -674,7 +788,7 @@ struct CameraRollManagerBasePhotoIdentifierImage { }; template -struct CameraRollManagerBasePhotoIdentifierImageBridging { +struct [[deprecated(\\"Use CameraRollManagerPhotoIdentifierImageBridging instead.\\")]] CameraRollManagerBasePhotoIdentifierImageBridging { static CameraRollManagerBasePhotoIdentifierImage fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -737,7 +851,7 @@ struct CameraRollManagerBasePhotoIdentifierImageBridging { #pragma mark - CameraRollManagerBasePhotoIdentifier template -struct CameraRollManagerBasePhotoIdentifier { +struct [[deprecated(\\"Use CameraRollManagerPhotoIdentifier instead.\\")]] CameraRollManagerBasePhotoIdentifier { P0 node; bool operator==(const CameraRollManagerBasePhotoIdentifier &other) const { return node == other.node; @@ -745,7 +859,7 @@ struct CameraRollManagerBasePhotoIdentifier { }; template -struct CameraRollManagerBasePhotoIdentifierBridging { +struct [[deprecated(\\"Use CameraRollManagerPhotoIdentifierBridging instead.\\")]] CameraRollManagerBasePhotoIdentifierBridging { static CameraRollManagerBasePhotoIdentifier fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -776,7 +890,7 @@ struct CameraRollManagerBasePhotoIdentifierBridging { #pragma mark - CameraRollManagerBasePhotoIdentifiersPage template -struct CameraRollManagerBasePhotoIdentifiersPage { +struct [[deprecated(\\"Use CameraRollManagerPhotoIdentifiersPage instead.\\")]] CameraRollManagerBasePhotoIdentifiersPage { P0 edges; P1 page_info; bool operator==(const CameraRollManagerBasePhotoIdentifiersPage &other) const { @@ -785,7 +899,7 @@ struct CameraRollManagerBasePhotoIdentifiersPage { }; template -struct CameraRollManagerBasePhotoIdentifiersPageBridging { +struct [[deprecated(\\"Use CameraRollManagerPhotoIdentifiersPageBridging instead.\\")]] CameraRollManagerBasePhotoIdentifiersPageBridging { static CameraRollManagerBasePhotoIdentifiersPage fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -822,7 +936,7 @@ struct CameraRollManagerBasePhotoIdentifiersPageBridging { #pragma mark - CameraRollManagerBaseGetPhotosParams template -struct CameraRollManagerBaseGetPhotosParams { +struct [[deprecated(\\"Use CameraRollManagerGetPhotosParams instead.\\")]] CameraRollManagerBaseGetPhotosParams { P0 first; P1 after; P2 groupName; @@ -836,7 +950,7 @@ struct CameraRollManagerBaseGetPhotosParams { }; template -struct CameraRollManagerBaseGetPhotosParamsBridging { +struct [[deprecated(\\"Use CameraRollManagerGetPhotosParamsBridging instead.\\")]] CameraRollManagerBaseGetPhotosParamsBridging { static CameraRollManagerBaseGetPhotosParams fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -910,6 +1024,267 @@ struct CameraRollManagerBaseGetPhotosParamsBridging { } }; + +#pragma mark - CameraRollManagerPhotoIdentifierImage + +template +struct CameraRollManagerPhotoIdentifierImage { + P0 uri; + P1 playableDuration; + P2 width; + P3 height; + P4 isStored; + P5 filename; + bool operator==(const CameraRollManagerPhotoIdentifierImage &other) const { + return uri == other.uri && playableDuration == other.playableDuration && width == other.width && height == other.height && isStored == other.isStored && filename == other.filename; + } +}; + +template +struct CameraRollManagerPhotoIdentifierImageBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"uri\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"playableDuration\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"width\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"height\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"isStored\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"filename\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String uriToJs(jsi::Runtime &rt, decltype(types.uri) value) { + return bridging::toJs(rt, value); + } + + static double playableDurationToJs(jsi::Runtime &rt, decltype(types.playableDuration) value) { + return bridging::toJs(rt, value); + } + + static double widthToJs(jsi::Runtime &rt, decltype(types.width) value) { + return bridging::toJs(rt, value); + } + + static double heightToJs(jsi::Runtime &rt, decltype(types.height) value) { + return bridging::toJs(rt, value); + } + + static bool isStoredToJs(jsi::Runtime &rt, decltype(types.isStored) value) { + return bridging::toJs(rt, value); + } + + static jsi::String filenameToJs(jsi::Runtime &rt, decltype(types.filename) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"uri\\", bridging::toJs(rt, value.uri, jsInvoker)); + result.setProperty(rt, \\"playableDuration\\", bridging::toJs(rt, value.playableDuration, jsInvoker)); + result.setProperty(rt, \\"width\\", bridging::toJs(rt, value.width, jsInvoker)); + result.setProperty(rt, \\"height\\", bridging::toJs(rt, value.height, jsInvoker)); + if (value.isStored) { + result.setProperty(rt, \\"isStored\\", bridging::toJs(rt, value.isStored.value(), jsInvoker)); + } + result.setProperty(rt, \\"filename\\", bridging::toJs(rt, value.filename, jsInvoker)); + return result; + } +}; + + + +#pragma mark - CameraRollManagerPhotoIdentifier + +template +struct CameraRollManagerPhotoIdentifier { + P0 node; + bool operator==(const CameraRollManagerPhotoIdentifier &other) const { + return node == other.node; + } +}; + +template +struct CameraRollManagerPhotoIdentifierBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"node\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::Object nodeToJs(jsi::Runtime &rt, decltype(types.node) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"node\\", bridging::toJs(rt, value.node, jsInvoker)); + return result; + } +}; + + + +#pragma mark - CameraRollManagerPhotoIdentifiersPage + +template +struct CameraRollManagerPhotoIdentifiersPage { + P0 edges; + P1 page_info; + bool operator==(const CameraRollManagerPhotoIdentifiersPage &other) const { + return edges == other.edges && page_info == other.page_info; + } +}; + +template +struct CameraRollManagerPhotoIdentifiersPageBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"edges\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"page_info\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::Array edgesToJs(jsi::Runtime &rt, decltype(types.edges) value) { + return bridging::toJs(rt, value); + } + + static jsi::Object page_infoToJs(jsi::Runtime &rt, decltype(types.page_info) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"edges\\", bridging::toJs(rt, value.edges, jsInvoker)); + result.setProperty(rt, \\"page_info\\", bridging::toJs(rt, value.page_info, jsInvoker)); + return result; + } +}; + + + +#pragma mark - CameraRollManagerGetPhotosParams + +template +struct CameraRollManagerGetPhotosParams { + P0 first; + P1 after; + P2 groupName; + P3 groupTypes; + P4 assetType; + P5 maxSize; + P6 mimeTypes; + bool operator==(const CameraRollManagerGetPhotosParams &other) const { + return first == other.first && after == other.after && groupName == other.groupName && groupTypes == other.groupTypes && assetType == other.assetType && maxSize == other.maxSize && mimeTypes == other.mimeTypes; + } +}; + +template +struct CameraRollManagerGetPhotosParamsBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"first\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"after\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"groupName\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"groupTypes\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"assetType\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"maxSize\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"mimeTypes\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static double firstToJs(jsi::Runtime &rt, decltype(types.first) value) { + return bridging::toJs(rt, value); + } + + static jsi::String afterToJs(jsi::Runtime &rt, decltype(types.after) value) { + return bridging::toJs(rt, value); + } + + static jsi::String groupNameToJs(jsi::Runtime &rt, decltype(types.groupName) value) { + return bridging::toJs(rt, value); + } + + static jsi::String groupTypesToJs(jsi::Runtime &rt, decltype(types.groupTypes) value) { + return bridging::toJs(rt, value); + } + + static jsi::String assetTypeToJs(jsi::Runtime &rt, decltype(types.assetType) value) { + return bridging::toJs(rt, value); + } + + static double maxSizeToJs(jsi::Runtime &rt, decltype(types.maxSize) value) { + return bridging::toJs(rt, value); + } + + static jsi::Array mimeTypesToJs(jsi::Runtime &rt, decltype(types.mimeTypes) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"first\\", bridging::toJs(rt, value.first, jsInvoker)); + if (value.after) { + result.setProperty(rt, \\"after\\", bridging::toJs(rt, value.after.value(), jsInvoker)); + } + if (value.groupName) { + result.setProperty(rt, \\"groupName\\", bridging::toJs(rt, value.groupName.value(), jsInvoker)); + } + if (value.groupTypes) { + result.setProperty(rt, \\"groupTypes\\", bridging::toJs(rt, value.groupTypes.value(), jsInvoker)); + } + if (value.assetType) { + result.setProperty(rt, \\"assetType\\", bridging::toJs(rt, value.assetType.value(), jsInvoker)); + } + if (value.maxSize) { + result.setProperty(rt, \\"maxSize\\", bridging::toJs(rt, value.maxSize.value(), jsInvoker)); + } + if (value.mimeTypes) { + result.setProperty(rt, \\"mimeTypes\\", bridging::toJs(rt, value.mimeTypes.value(), jsInvoker)); + } + return result; + } +}; + class JSI_EXPORT NativeCameraRollManagerCxxSpecJSI : public TurboModule { protected: NativeCameraRollManagerCxxSpecJSI(std::shared_ptr jsInvoker); @@ -987,7 +1362,7 @@ private: #pragma mark - ExceptionsManagerBaseStackFrame template -struct ExceptionsManagerBaseStackFrame { +struct [[deprecated(\\"Use ExceptionsManagerStackFrame instead.\\")]] ExceptionsManagerBaseStackFrame { P0 column; P1 file; P2 lineNumber; @@ -999,7 +1374,7 @@ struct ExceptionsManagerBaseStackFrame { }; template -struct ExceptionsManagerBaseStackFrameBridging { +struct [[deprecated(\\"Use ExceptionsManagerStackFrameBridging instead.\\")]] ExceptionsManagerBaseStackFrameBridging { static ExceptionsManagerBaseStackFrame fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -1060,7 +1435,7 @@ struct ExceptionsManagerBaseStackFrameBridging { #pragma mark - ExceptionsManagerBaseExceptionData template -struct ExceptionsManagerBaseExceptionData { +struct [[deprecated(\\"Use ExceptionsManagerExceptionData instead.\\")]] ExceptionsManagerBaseExceptionData { P0 message; P1 originalMessage; P2 name; @@ -1075,7 +1450,7 @@ struct ExceptionsManagerBaseExceptionData { }; template -struct ExceptionsManagerBaseExceptionDataBridging { +struct [[deprecated(\\"Use ExceptionsManagerExceptionDataBridging instead.\\")]] ExceptionsManagerBaseExceptionDataBridging { static ExceptionsManagerBaseExceptionData fromJs( jsi::Runtime &rt, const jsi::Object &value, @@ -1145,6 +1520,172 @@ struct ExceptionsManagerBaseExceptionDataBridging { } }; + +#pragma mark - ExceptionsManagerStackFrame + +template +struct ExceptionsManagerStackFrame { + P0 column; + P1 file; + P2 lineNumber; + P3 methodName; + P4 collapse; + bool operator==(const ExceptionsManagerStackFrame &other) const { + return column == other.column && file == other.file && lineNumber == other.lineNumber && methodName == other.methodName && collapse == other.collapse; + } +}; + +template +struct ExceptionsManagerStackFrameBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"column\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"file\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"lineNumber\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"methodName\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"collapse\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static double columnToJs(jsi::Runtime &rt, decltype(types.column) value) { + return bridging::toJs(rt, value); + } + + static jsi::String fileToJs(jsi::Runtime &rt, decltype(types.file) value) { + return bridging::toJs(rt, value); + } + + static double lineNumberToJs(jsi::Runtime &rt, decltype(types.lineNumber) value) { + return bridging::toJs(rt, value); + } + + static jsi::String methodNameToJs(jsi::Runtime &rt, decltype(types.methodName) value) { + return bridging::toJs(rt, value); + } + + static bool collapseToJs(jsi::Runtime &rt, decltype(types.collapse) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.column) { + result.setProperty(rt, \\"column\\", bridging::toJs(rt, value.column.value(), jsInvoker)); + } + result.setProperty(rt, \\"file\\", bridging::toJs(rt, value.file, jsInvoker)); + if (value.lineNumber) { + result.setProperty(rt, \\"lineNumber\\", bridging::toJs(rt, value.lineNumber.value(), jsInvoker)); + } + result.setProperty(rt, \\"methodName\\", bridging::toJs(rt, value.methodName, jsInvoker)); + if (value.collapse) { + result.setProperty(rt, \\"collapse\\", bridging::toJs(rt, value.collapse.value(), jsInvoker)); + } + return result; + } +}; + + + +#pragma mark - ExceptionsManagerExceptionData + +template +struct ExceptionsManagerExceptionData { + P0 message; + P1 originalMessage; + P2 name; + P3 componentStack; + P4 stack; + P5 id; + P6 isFatal; + P7 extraData; + bool operator==(const ExceptionsManagerExceptionData &other) const { + return message == other.message && originalMessage == other.originalMessage && name == other.name && componentStack == other.componentStack && stack == other.stack && id == other.id && isFatal == other.isFatal && extraData == other.extraData; + } +}; + +template +struct ExceptionsManagerExceptionDataBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"message\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"originalMessage\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"componentStack\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"stack\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"id\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"isFatal\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"extraData\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String messageToJs(jsi::Runtime &rt, decltype(types.message) value) { + return bridging::toJs(rt, value); + } + + static jsi::String originalMessageToJs(jsi::Runtime &rt, decltype(types.originalMessage) value) { + return bridging::toJs(rt, value); + } + + static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } + + static jsi::String componentStackToJs(jsi::Runtime &rt, decltype(types.componentStack) value) { + return bridging::toJs(rt, value); + } + + static jsi::Array stackToJs(jsi::Runtime &rt, decltype(types.stack) value) { + return bridging::toJs(rt, value); + } + + static double idToJs(jsi::Runtime &rt, decltype(types.id) value) { + return bridging::toJs(rt, value); + } + + static bool isFatalToJs(jsi::Runtime &rt, decltype(types.isFatal) value) { + return bridging::toJs(rt, value); + } + + static jsi::Object extraDataToJs(jsi::Runtime &rt, decltype(types.extraData) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"message\\", bridging::toJs(rt, value.message, jsInvoker)); + result.setProperty(rt, \\"originalMessage\\", bridging::toJs(rt, value.originalMessage, jsInvoker)); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + result.setProperty(rt, \\"componentStack\\", bridging::toJs(rt, value.componentStack, jsInvoker)); + result.setProperty(rt, \\"stack\\", bridging::toJs(rt, value.stack, jsInvoker)); + result.setProperty(rt, \\"id\\", bridging::toJs(rt, value.id, jsInvoker)); + result.setProperty(rt, \\"isFatal\\", bridging::toJs(rt, value.isFatal, jsInvoker)); + if (value.extraData) { + result.setProperty(rt, \\"extraData\\", bridging::toJs(rt, value.extraData.value(), jsInvoker)); + } + return result; + } +}; + class JSI_EXPORT NativeExceptionsManagerCxxSpecJSI : public TurboModule { protected: NativeExceptionsManagerCxxSpecJSI(std::shared_ptr jsInvoker); diff --git a/packages/react-native-gradle-plugin/build.gradle.kts b/packages/react-native-gradle-plugin/build.gradle.kts index c4a31beb010e19..9346508f497062 100644 --- a/packages/react-native-gradle-plugin/build.gradle.kts +++ b/packages/react-native-gradle-plugin/build.gradle.kts @@ -26,6 +26,10 @@ gradlePlugin { id = "com.facebook.react" implementationClass = "com.facebook.react.ReactPlugin" } + create("reactrootproject") { + id = "com.facebook.react.rootproject" + implementationClass = "com.facebook.react.ReactRootProjectPlugin" + } } } diff --git a/packages/react-native-gradle-plugin/gradle/libs.versions.toml b/packages/react-native-gradle-plugin/gradle/libs.versions.toml index f2a1d2edab765a..985424bfa011d1 100644 --- a/packages/react-native-gradle-plugin/gradle/libs.versions.toml +++ b/packages/react-native-gradle-plugin/gradle/libs.versions.toml @@ -1,10 +1,10 @@ [versions] -agp = "8.1.1" +agp = "8.2.0" gson = "2.8.9" guava = "31.0.1-jre" javapoet = "1.13.0" junit = "4.13.2" -kotlin = "1.8.0" +kotlin = "1.8.22" [libraries] kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } diff --git a/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar index 7f93135c49b765..d64cd4917707c1 100644 Binary files a/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar and b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar differ diff --git a/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties index 8838ba97ba0914..e6aba2515d5428 100644 --- a/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties +++ b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactRootProjectPlugin.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactRootProjectPlugin.kt new file mode 100644 index 00000000000000..5f232cd0e581a5 --- /dev/null +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactRootProjectPlugin.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react + +import org.gradle.api.Plugin +import org.gradle.api.Project + +/** + * Gradle plugin applied to the `android/build.gradle` file. + * + * This plugin allows to specify project wide configurations that can be applied to both apps and + * libraries before they're evaluated. + */ +class ReactRootProjectPlugin : Plugin { + override fun apply(project: Project) { + project.subprojects { + // As the :app project (i.e. ReactPlugin) configures both namespaces and JVM toolchains + // for libraries, its evaluation must happen before the libraries' evaluation. + // Eventually the configuration of namespace/JVM toolchain can be moved inside this plugin. + if (it.path != ":app") { + it.evaluationDependsOn(":app") + } + } + } +} diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt index 3c65387a4036c9..828a145b0076a0 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt @@ -67,6 +67,8 @@ abstract class GenerateCodegenSchemaTask : Exec() { .cliPath(workingDir), "--platform", "android", + "--exclude", + "NativeSampleTurboModule", generatedSchemaFile.get().asFile.cliPath(workingDir), jsRootDir.asFile.get().cliPath(workingDir), )) diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt index 9434b5a3c52f84..d24a9ee99021eb 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt @@ -102,6 +102,7 @@ internal object NdkConfiguratorUtils { "**/libreact_debug.so", "**/libreact_nativemodule_core.so", "**/libreact_newarchdefaults.so", + "**/libreact_cxxreactpackage.so", "**/libreact_render_componentregistry.so", "**/libreact_render_core.so", "**/libreact_render_debug.so", diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTaskTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTaskTest.kt index b97c1b29a204f6..0d0f159923821a 100644 --- a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTaskTest.kt +++ b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTaskTest.kt @@ -145,6 +145,8 @@ class GenerateCodegenSchemaTaskTest { File(codegenDir, "lib/cli/combine/combine-js-to-schema-cli.js").toString(), "--platform", "android", + "--exclude", + "NativeSampleTurboModule", File(outputDir, "schema.json").toString(), jsRootDir.toString(), ), @@ -180,6 +182,8 @@ class GenerateCodegenSchemaTaskTest { .path, "--platform", "android", + "--exclude", + "NativeSampleTurboModule", File(outputDir, "schema.json").relativeTo(project.projectDir).path, jsRootDir.relativeTo(project.projectDir).path, ), diff --git a/packages/react-native/Libraries/Animated/components/AnimatedScrollView.js b/packages/react-native/Libraries/Animated/components/AnimatedScrollView.js index ee746c3b4e2e13..029563d4bb9059 100644 --- a/packages/react-native/Libraries/Animated/components/AnimatedScrollView.js +++ b/packages/react-native/Libraries/Animated/components/AnimatedScrollView.js @@ -108,7 +108,7 @@ const AnimatedScrollViewWithInvertedRefreshControl = React.forwardRef( Props, Instance, >(intermediatePropsForScrollView); - const ref = useMergeRefs(scrollViewRef, forwardedRef); + const ref = useMergeRefs(scrollViewRef, forwardedRef); return ( // $FlowFixMe[incompatible-use] Investigate useAnimatedProps return value diff --git a/packages/react-native/Libraries/Animated/createAnimatedComponent.js b/packages/react-native/Libraries/Animated/createAnimatedComponent.js index 78645a36f187bc..d859209037d13f 100644 --- a/packages/react-native/Libraries/Animated/createAnimatedComponent.js +++ b/packages/react-native/Libraries/Animated/createAnimatedComponent.js @@ -35,8 +35,7 @@ export default function createAnimatedComponent( // $FlowFixMe[incompatible-call] props, ); - // $FlowFixMe[incompatible-call] - const ref = useMergeRefs(callbackRef, forwardedRef); + const ref = useMergeRefs(callbackRef, forwardedRef); // Some components require explicit passthrough values for animation // to work properly. For example, if an animated component is diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h index 71739d159ff40c..f6a35caf3f0cb3 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h +++ b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h @@ -109,7 +109,6 @@ /// @return: `YES` to use RuntimeScheduler, `NO` to use JavaScript scheduler. The default value is `YES`. - (BOOL)runtimeSchedulerEnabled; -#if RCT_NEW_ARCH_ENABLED @property (nonatomic, strong) RCTSurfacePresenterBridgeAdapter *bridgeAdapter; /// This method returns a map of Component Descriptors and Components classes that needs to be registered in the @@ -139,6 +138,4 @@ /// Return the bundle URL for the main bundle. - (NSURL *)bundleURL; -#endif - @end diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm index 82e1911fe12246..13aee73117cb1f 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm @@ -13,7 +13,6 @@ #import "RCTAppSetupUtils.h" #import "RCTLegacyInteropComponents.h" -#if RCT_NEW_ARCH_ENABLED #if RN_DISABLE_OSS_PLUGIN_HEADER #import #else @@ -38,7 +37,7 @@ #import #import #import -#import +#import static NSString *const kRNConcurrentRoot = @"concurrentRoot"; @@ -51,19 +50,13 @@ @interface RCTAppDelegate () < } @end -#endif - static NSDictionary *updateInitialProps(NSDictionary *initialProps, BOOL isFabricEnabled) { -#ifdef RCT_NEW_ARCH_ENABLED NSMutableDictionary *mutableProps = [initialProps mutableCopy] ?: [NSMutableDictionary new]; // Hardcoding the Concurrent Root as it it not recommended to // have the concurrentRoot turned off when Fabric is enabled. mutableProps[kRNConcurrentRoot] = @(isFabricEnabled); return mutableProps; -#else - return initialProps; -#endif } @interface RCTAppDelegate () { @@ -72,12 +65,9 @@ @interface RCTAppDelegate () { @end @implementation RCTAppDelegate { -#if RCT_NEW_ARCH_ENABLED RCTHost *_reactHost; -#endif } -#if RCT_NEW_ARCH_ENABLED - (instancetype)init { if (self = [super init]) { @@ -87,25 +77,19 @@ - (instancetype)init } return self; } -#endif - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - BOOL enableTM = NO; - BOOL enableBridgeless = NO; - BOOL fabricEnabled = NO; -#if RCT_NEW_ARCH_ENABLED - enableTM = self.turboModuleEnabled; - enableBridgeless = self.bridgelessEnabled; - fabricEnabled = [self fabricEnabled]; -#endif + BOOL enableTM = self.turboModuleEnabled; + BOOL enableBridgeless = self.bridgelessEnabled; + BOOL fabricEnabled = self.fabricEnabled; + NSDictionary *initProps = updateInitialProps([self prepareInitialProps], fabricEnabled); RCTAppSetupPrepareApp(application, enableTM); UIView *rootView; if (enableBridgeless) { -#if RCT_NEW_ARCH_ENABLED // Enable native view config interop only if both bridgeless mode and Fabric is enabled. RCTSetUseNativeViewConfigsInBridgelessMode(fabricEnabled); @@ -123,19 +107,18 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( sizeMeasureMode:RCTSurfaceSizeMeasureModeWidthExact | RCTSurfaceSizeMeasureModeHeightExact]; rootView = (RCTRootView *)surfaceHostingProxyRootView; -#endif } else { if (!self.bridge) { self.bridge = [self createBridgeWithDelegate:self launchOptions:launchOptions]; } -#if RCT_NEW_ARCH_ENABLED - self.bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:self.bridge - contextContainer:_contextContainer]; - self.bridge.surfacePresenter = self.bridgeAdapter.surfacePresenter; + if ([self newArchEnabled]) { + self.bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:self.bridge + contextContainer:_contextContainer]; + self.bridge.surfacePresenter = self.bridgeAdapter.surfacePresenter; - [self unstable_registerLegacyComponents]; - [RCTComponentViewFactory currentComponentViewFactory].thirdPartyFabricComponentsProvider = self; -#endif + [self unstable_registerLegacyComponents]; + [RCTComponentViewFactory currentComponentViewFactory].thirdPartyFabricComponentsProvider = self; + } rootView = [self createRootViewWithBridge:self.bridge moduleName:self.moduleName initProps:initProps]; } @@ -170,10 +153,7 @@ - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initProps:(NSDictionary *)initProps { - BOOL enableFabric = NO; -#if RCT_NEW_ARCH_ENABLED - enableFabric = self.fabricEnabled; -#endif + BOOL enableFabric = self.fabricEnabled; UIView *rootView = RCTAppSetupDefaultRootView(bridge, moduleName, initProps, enableFabric); rootView.backgroundColor = [UIColor systemBackgroundColor]; @@ -209,49 +189,44 @@ - (void)windowScene:(UIWindowScene *)windowScene - (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge { _runtimeScheduler = std::make_shared(RCTRuntimeExecutorFromBridge(bridge)); -#if RCT_NEW_ARCH_ENABLED - std::shared_ptr callInvoker = - std::make_shared(_runtimeScheduler); - RCTTurboModuleManager *turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge - delegate:self - jsInvoker:callInvoker]; - _contextContainer->erase("RuntimeScheduler"); - _contextContainer->insert("RuntimeScheduler", _runtimeScheduler); - return RCTAppSetupDefaultJsExecutorFactory(bridge, turboModuleManager, _runtimeScheduler); -#else - return RCTAppSetupJsExecutorFactoryForOldArch(bridge, _runtimeScheduler); -#endif + if ([self newArchEnabled]) { + std::shared_ptr callInvoker = + std::make_shared(_runtimeScheduler); + RCTTurboModuleManager *turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge + delegate:self + jsInvoker:callInvoker]; + _contextContainer->erase("RuntimeScheduler"); + _contextContainer->insert("RuntimeScheduler", _runtimeScheduler); + return RCTAppSetupDefaultJsExecutorFactory(bridge, turboModuleManager, _runtimeScheduler); + } else { + return RCTAppSetupJsExecutorFactoryForOldArch(bridge, _runtimeScheduler); + } } -#if RCT_NEW_ARCH_ENABLED - -#pragma mark - RCTTurboModuleManagerDelegate +#pragma mark - New Arch Enabled settings -- (Class)getModuleClassFromName:(const char *)name +- (BOOL)newArchEnabled { -#if RN_DISABLE_OSS_PLUGIN_HEADER - return RCTTurboModulePluginClassProvider(name); +#if USE_NEW_ARCH + return YES; #else - return RCTCoreModulesClassProvider(name); + return NO; #endif } -- (std::shared_ptr)getTurboModule:(const std::string &)name - jsInvoker:(std::shared_ptr)jsInvoker +- (BOOL)turboModuleEnabled { - return nullptr; + return [self newArchEnabled]; } -- (std::shared_ptr)getTurboModule:(const std::string &)name - initParams: - (const facebook::react::ObjCTurboModule::InitParams &)params +- (BOOL)fabricEnabled { - return nullptr; + return [self newArchEnabled]; } -- (id)getModuleInstanceFromClass:(Class)moduleClass +- (BOOL)bridgelessEnabled { - return RCTAppSetupDefaultModuleFromClass(moduleClass); + return NO; } #pragma mark - RCTComponentViewFactoryComponentProvider @@ -261,21 +236,33 @@ - (Class)getModuleClassFromName:(const char *)name return @{}; } -#pragma mark - New Arch Enabled settings +#pragma mark - RCTTurboModuleManagerDelegate -- (BOOL)turboModuleEnabled +- (Class)getModuleClassFromName:(const char *)name { - return YES; +#if RN_DISABLE_OSS_PLUGIN_HEADER + return RCTTurboModulePluginClassProvider(name); +#else + return RCTCoreModulesClassProvider(name); +#endif } -- (BOOL)fabricEnabled +- (std::shared_ptr)getTurboModule:(const std::string &)name + jsInvoker:(std::shared_ptr)jsInvoker { - return YES; + return nullptr; } -- (BOOL)bridgelessEnabled +- (std::shared_ptr)getTurboModule:(const std::string &)name + initParams: + (const facebook::react::ObjCTurboModule::InitParams &)params { - return NO; + return nullptr; +} + +- (id)getModuleInstanceFromClass:(Class)moduleClass +{ + return RCTAppSetupDefaultModuleFromClass(moduleClass); } #pragma mark - New Arch Utilities @@ -293,8 +280,8 @@ - (void)createReactHost _reactHost = [[RCTHost alloc] initWithBundleURL:[self bundleURL] hostDelegate:nil turboModuleManagerDelegate:self - jsEngineProvider:^std::shared_ptr() { - return [weakSelf createJSEngineInstance]; + jsEngineProvider:^std::shared_ptr() { + return [weakSelf createJSRuntimeFactory]; }]; [_reactHost setBundleURLProvider:^NSURL *() { return [weakSelf bundleURL]; @@ -303,7 +290,7 @@ - (void)createReactHost [_reactHost start]; } -- (std::shared_ptr)createJSEngineInstance +- (std::shared_ptr)createJSRuntimeFactory { #if USE_HERMES return std::make_shared(_reactNativeConfig, nullptr); @@ -324,6 +311,4 @@ - (NSURL *)bundleURL return nullptr; } -#endif - @end diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.h b/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.h index e1c69078409caf..d661fb4355c1c1 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.h +++ b/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.h @@ -26,28 +26,23 @@ #endif #endif -#if RCT_NEW_ARCH_ENABLED #import -#endif // Forward declaration to decrease compilation coupling namespace facebook::react { class RuntimeScheduler; } -#if RCT_NEW_ARCH_ENABLED - RCT_EXTERN id RCTAppSetupDefaultModuleFromClass(Class moduleClass); std::unique_ptr RCTAppSetupDefaultJsExecutorFactory( RCTBridge *bridge, RCTTurboModuleManager *turboModuleManager, const std::shared_ptr &runtimeScheduler); -#else + std::unique_ptr RCTAppSetupJsExecutorFactoryForOldArch( RCTBridge *bridge, const std::shared_ptr &runtimeScheduler); -#endif #endif // __cplusplus diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm b/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm index 6241f62831cf40..3127588b7de0a1 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm @@ -11,7 +11,6 @@ #import #import -#if RCT_NEW_ARCH_ENABLED // Turbo Module #import #import @@ -24,13 +23,10 @@ // Fabric #import #import -#endif void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled) { -#if RCT_NEW_ARCH_ENABLED RCTEnableTurboModule(turboModuleEnabled); -#endif #if DEBUG // Disable idle timer in dev builds to avoid putting application in background and complicating @@ -42,18 +38,15 @@ void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled) UIView * RCTAppSetupDefaultRootView(RCTBridge *bridge, NSString *moduleName, NSDictionary *initialProperties, BOOL fabricEnabled) { -#if RCT_NEW_ARCH_ENABLED if (fabricEnabled) { id surface = [[RCTFabricSurface alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]; return [[RCTSurfaceHostingProxyRootView alloc] initWithSurface:surface]; } -#endif return [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]; } -#if RCT_NEW_ARCH_ENABLED id RCTAppSetupDefaultModuleFromClass(Class moduleClass) { // Set up the default RCTImageLoader and RCTNetworking modules. @@ -114,8 +107,6 @@ void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled) })); } -#else // else !RCT_NEW_ARCH_ENABLED - std::unique_ptr RCTAppSetupJsExecutorFactoryForOldArch( RCTBridge *bridge, const std::shared_ptr &runtimeScheduler) @@ -134,4 +125,3 @@ void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled) } })); } -#endif // end RCT_NEW_ARCH_ENABLED diff --git a/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec b/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec index 815c03705ed402..fe4a4bbd021528 100644 --- a/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec +++ b/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec @@ -19,14 +19,13 @@ end folly_flags = ' -DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_CFG_NO_COROUTINES=1 -DFOLLY_HAVE_CLOCK_GETTIME=1' folly_compiler_flags = folly_flags + ' ' + '-Wno-comma -Wno-shorten-64-to-32' -is_new_arch_enabled = ENV["RCT_NEW_ARCH_ENABLED"] == "1" +is_new_arch_enabled = ENV["USE_NEW_ARCH"] == "1" use_hermes = ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == '1' -new_arch_enabled_flag = (is_new_arch_enabled ? " -DRCT_NEW_ARCH_ENABLED" : "") +new_arch_enabled_flag = (is_new_arch_enabled ? " -DUSE_NEW_ARCH" : "") is_fabric_enabled = is_new_arch_enabled || ENV["RCT_FABRIC_ENABLED"] -fabric_flag = (is_fabric_enabled ? " -DRN_FABRIC_ENABLED" : "") hermes_flag = (use_hermes ? " -DUSE_HERMES" : "") -other_cflags = "$(inherited)" + folly_flags + new_arch_enabled_flag + fabric_flag + hermes_flag +other_cflags = "$(inherited)" + folly_flags + new_arch_enabled_flag + hermes_flag header_search_paths = [ "$(PODS_TARGET_SRCROOT)/../../ReactCommon", @@ -81,42 +80,33 @@ Pod::Spec.new do |s| add_dependency(s, "React-NativeModulesApple") add_dependency(s, "React-runtimescheduler") add_dependency(s, "React-RCTFabric", :framework_name => "RCTFabric") - - if is_new_arch_enabled - add_dependency(s, "React-RuntimeCore") - add_dependency(s, "React-RuntimeApple") - if use_hermes - s.dependency "React-RuntimeHermes" - end - end + add_dependency(s, "React-RuntimeCore") + add_dependency(s, "React-RuntimeApple") + add_dependency(s, "React-Fabric", :additional_framework_paths => ["react/renderer/components/view/platform/cxx"]) + add_dependency(s, "React-graphics", :additional_framework_paths => ["react/renderer/graphics/platform/ios"]) + add_dependency(s, "React-utils") + add_dependency(s, "React-debug") + add_dependency(s, "React-rendererdebug") if use_hermes s.dependency "React-hermes" + s.dependency "React-RuntimeHermes" else s.dependency "React-jsc" end - if is_new_arch_enabled - add_dependency(s, "React-Fabric", :additional_framework_paths => ["react/renderer/components/view/platform/cxx"]) - add_dependency(s, "React-graphics", :additional_framework_paths => ["react/renderer/graphics/platform/ios"]) - add_dependency(s, "React-utils") - add_dependency(s, "React-debug") - add_dependency(s, "React-rendererdebug") - - rel_path_from_pods_root_to_app = Pathname.new(ENV['APP_PATH']).relative_path_from(Pod::Config.instance.installation_root) - rel_path_from_pods_to_app = Pathname.new(ENV['APP_PATH']).relative_path_from(File.join(Pod::Config.instance.installation_root, 'Pods')) + rel_path_from_pods_root_to_app = Pathname.new(ENV['APP_PATH']).relative_path_from(Pod::Config.instance.installation_root) + rel_path_from_pods_to_app = Pathname.new(ENV['APP_PATH']).relative_path_from(File.join(Pod::Config.instance.installation_root, 'Pods')) - - s.script_phases = { - :name => "Generate Legacy Components Interop", - :script => " + s.script_phases = { + :name => "Generate Legacy Components Interop", + :script => " WITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\" source $WITH_ENVIRONMENT ${NODE_BINARY} ${REACT_NATIVE_PATH}/scripts/codegen/generate-legacy-interop-components.js -p #{rel_path_from_pods_to_app} -o ${REACT_NATIVE_PATH}/Libraries/AppDelegate - ", - :execution_position => :before_compile, - :input_files => ["#{rel_path_from_pods_root_to_app}/react-native.config.js"], - :output_files => ["${REACT_NATIVE_PATH}/Libraries/AppDelegate/RCTLegacyInteropComponents.mm"], - } - end + ", + :execution_position => :before_compile, + :input_files => ["#{rel_path_from_pods_root_to_app}/react-native.config.js"], + :output_files => ["${REACT_NATIVE_PATH}/Libraries/AppDelegate/RCTLegacyInteropComponents.mm"], + } end diff --git a/packages/react-native/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js b/packages/react-native/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js index 7394582902dcf0..0d79257ae1c382 100644 --- a/packages/react-native/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js +++ b/packages/react-native/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js @@ -21,16 +21,16 @@ type NativeProps = $ReadOnly<{| /** * Whether the indicator should hide when not animating (true by default). * - * See https://reactnative.dev/docs/activityindicator#hideswhenstopped + * See https://reactnative.dev/docs/activityindicator#hideswhenstopped-ios */ - hidesWhenStopped?: WithDefault, + hidesWhenStopped?: WithDefault, /** * Whether to show the indicator (true, the default) or hide it (false). * * See https://reactnative.dev/docs/activityindicator#animating */ - animating?: WithDefault, + animating?: WithDefault, /** * The foreground color of the spinner (default is gray). diff --git a/packages/react-native/Libraries/Components/ScrollView/ScrollView.js b/packages/react-native/Libraries/Components/ScrollView/ScrollView.js index 2e2264afedbd2b..30ec946848cc63 100644 --- a/packages/react-native/Libraries/Components/ScrollView/ScrollView.js +++ b/packages/react-native/Libraries/Components/ScrollView/ScrollView.js @@ -1148,21 +1148,6 @@ class ScrollView extends React.Component { } _handleScroll = (e: ScrollEvent) => { - if (__DEV__) { - if ( - this.props.onScroll && - this.props.scrollEventThrottle == null && - Platform.OS === 'ios' - ) { - console.log( - 'You specified `onScroll` on a but not ' + - '`scrollEventThrottle`. You will only receive one event. ' + - 'Using `16` you get all the events but be aware that it may ' + - "cause frame drops, use a bigger number if you don't need as " + - 'much precision.', - ); - } - } this._observedScrollSinceBecomingResponder = true; this.props.onScroll && this.props.onScroll(e); }; diff --git a/packages/react-native/Libraries/Components/ScrollView/ScrollViewStickyHeader.js b/packages/react-native/Libraries/Components/ScrollView/ScrollViewStickyHeader.js index 0cdebf840d004f..3b26ae87fed40a 100644 --- a/packages/react-native/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +++ b/packages/react-native/Libraries/Components/ScrollView/ScrollViewStickyHeader.js @@ -67,8 +67,7 @@ const ScrollViewStickyHeaderWithForwardedRef: React.AbstractComponent< }, []); const ref: (React.ElementRef | null) => void = // $FlowFixMe[incompatible-type] - Ref is mutated by `callbackRef`. - // $FlowFixMe[incompatible-call] - useMergeRefs(callbackRef, forwardedRef); + useMergeRefs(callbackRef, forwardedRef); const offset = useMemo( () => diff --git a/packages/react-native/Libraries/Components/Switch/Switch.js b/packages/react-native/Libraries/Components/Switch/Switch.js index 24f3b841aee842..af27bd58adab74 100644 --- a/packages/react-native/Libraries/Components/Switch/Switch.js +++ b/packages/react-native/Libraries/Components/Switch/Switch.js @@ -155,7 +155,6 @@ const SwitchWithForwardedRef: React.AbstractComponent< typeof SwitchNativeComponent | typeof AndroidSwitchNativeComponent, > | null>(null); - // $FlowFixMe[incompatible-call] const ref = useMergeRefs(nativeSwitchRef, forwardedRef); const [native, setNative] = React.useState({value: (null: ?boolean)}); diff --git a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js index 55b770d26a35ef..f5d06e24595213 100644 --- a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +++ b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js @@ -485,6 +485,11 @@ export type NativeProps = $ReadOnly<{| */ selectionColor?: ?ColorValue, + /** + * The text selection handle color. + */ + selectionHandleColor?: ?ColorValue, + /** * The start and end of the text input's selection. Set start and end to * the same value to position the cursor. @@ -692,6 +697,9 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = { fontStyle: true, textShadowOffset: true, selectionColor: {process: require('../../StyleSheet/processColor').default}, + selectionHandleColor: { + process: require('../../StyleSheet/processColor').default, + }, placeholderTextColor: { process: require('../../StyleSheet/processColor').default, }, diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts index 80db8f0a652225..7234cbb3c325c5 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts @@ -336,6 +336,14 @@ export interface TextInputAndroidProps { */ cursorColor?: ColorValue | null | undefined; + /** + * When provided it will set the color of the selection handles when highlighting text. + * Unlike the behavior of `selectionColor` the handle color will be set independently + * from the color of the text selection box. + * @platform android + */ + selectionHandleColor?: ColorValue | null | undefined; + /** * Determines whether the individual fields in your app should be included in a * view structure for autofill purposes on Android API Level 26+. Defaults to auto. diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js index 0eb8f578d65879..638acd7c7925a2 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js @@ -332,6 +332,14 @@ type AndroidProps = $ReadOnly<{| */ cursorColor?: ?ColorValue, + /** + * When provided it will set the color of the selection handles when highlighting text. + * Unlike the behavior of `selectionColor` the handle color will be set independently + * from the color of the text selection box. + * @platform android + */ + selectionHandleColor?: ?ColorValue, + /** * When `false`, if there is a small amount of space available around a text input * (e.g. landscape orientation on a phone), the OS may choose to have the user edit diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index 3e0d8bf7681dd3..57eebf7c7517e1 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -917,6 +917,12 @@ export type Props = $ReadOnly<{| */ selectionColor?: ?ColorValue, + /** + * The text selection handle color. + * @platform android + */ + selectionHandleColor?: ?ColorValue, + /** * If `true`, all text will automatically be selected on focus. */ @@ -1111,6 +1117,9 @@ function InternalTextInput(props: Props): React.Node { id, tabIndex, selection: propsSelection, + selectionColor, + selectionHandleColor, + cursorColor, ...otherProps } = props; @@ -1278,10 +1287,7 @@ function InternalTextInput(props: Props): React.Node { [mostRecentEventCount, viewCommands], ); - const ref = useMergeRefs( - setLocalRef, - props.forwardedRef, - ); + const ref = useMergeRefs(setLocalRef, props.forwardedRef); const _onChange = (event: ChangeEvent) => { const currentText = event.nativeEvent.text; @@ -1506,7 +1512,15 @@ function InternalTextInput(props: Props): React.Node { if (childCount > 1) { children = {children}; } - + // For consistency with iOS set cursor/selectionHandle color as selectionColor + const colorProps = { + selectionColor, + selectionHandleColor: + selectionHandleColor === undefined + ? selectionColor + : selectionHandleColor, + cursorColor: cursorColor === undefined ? selectionColor : cursorColor, + }; textInput = ( /* $FlowFixMe[prop-missing] the types for AndroidTextInput don't match up * exactly with the props for TextInput. This will need to get fixed */ @@ -1520,6 +1534,7 @@ function InternalTextInput(props: Props): React.Node { // $FlowFixMe[incompatible-type] - Figure out imperative + forward refs. ref={ref} {...otherProps} + {...colorProps} {...eventHandlers} accessibilityState={_accessibilityState} accessibilityLabelledBy={_accessibilityLabelledBy} diff --git a/packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js b/packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js index 57c70fd5f28c75..94ded259e1249e 100644 --- a/packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js +++ b/packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js @@ -8,26 +8,24 @@ * @format */ +import type {Overlay} from '../../Debugging/DebuggingOverlayNativeComponent'; import type { InstanceFromReactDevTools, ReactDevToolsAgent, } from '../../Types/ReactDevToolsTypes'; -import type {Overlay} from './TraceUpdateOverlayNativeComponent'; +import DebuggingOverlayNativeComponent, { + Commands, +} from '../../Debugging/DebuggingOverlayNativeComponent'; import UIManager from '../../ReactNative/UIManager'; import processColor from '../../StyleSheet/processColor'; import StyleSheet from '../../StyleSheet/StyleSheet'; -import Platform from '../../Utilities/Platform'; import View from '../View/View'; -import TraceUpdateOverlayNativeComponent, { - Commands, -} from './TraceUpdateOverlayNativeComponent'; import * as React from 'react'; const {useEffect, useRef, useState} = React; const isNativeComponentReady = - Platform.OS === 'android' && - UIManager.hasViewManagerConfig('TraceUpdateOverlay'); + UIManager.hasViewManagerConfig('DebuggingOverlay'); type Props = { reactDevToolsAgent: ReactDevToolsAgent, @@ -39,13 +37,13 @@ export default function TraceUpdateOverlay({ const [overlayDisabled, setOverlayDisabled] = useState(false); useEffect(() => { - if (!isNativeComponentReady) { - return; - } - const drawTraceUpdates = ( nodesToDraw: Array<{node: InstanceFromReactDevTools, color: string}> = [], ) => { + if (!isNativeComponentReady) { + return; + } + // If overlay is disabled before, now it's enabled. setOverlayDisabled(false); @@ -113,13 +111,13 @@ export default function TraceUpdateOverlay({ }, [reactDevToolsAgent]); const nativeComponentRef = - useRef>(null); + useRef>(null); return ( !overlayDisabled && isNativeComponentReady && ( - diff --git a/packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlayNativeComponent.js b/packages/react-native/Libraries/Debugging/DebuggingOverlayNativeComponent.js similarity index 62% rename from packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlayNativeComponent.js rename to packages/react-native/Libraries/Debugging/DebuggingOverlayNativeComponent.js index 837223e3774b2d..0e2f95514583e9 100644 --- a/packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlayNativeComponent.js +++ b/packages/react-native/Libraries/Debugging/DebuggingOverlayNativeComponent.js @@ -8,18 +8,18 @@ * @format */ -import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; -import type {ProcessedColorValue} from '../../StyleSheet/processColor'; -import type {ViewProps} from '../View/ViewPropTypes'; +import type {ViewProps} from '../Components/View/ViewPropTypes'; +import type {HostComponent} from '../Renderer/shims/ReactNativeTypes'; +import type {ProcessedColorValue} from '../StyleSheet/processColor'; -import codegenNativeCommands from '../../Utilities/codegenNativeCommands'; -import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; +import codegenNativeCommands from '../Utilities/codegenNativeCommands'; +import codegenNativeComponent from '../Utilities/codegenNativeComponent'; import * as React from 'react'; type NativeProps = $ReadOnly<{| ...ViewProps, |}>; -export type TraceUpdateOverlayNativeComponentType = HostComponent; +export type DebuggingOverlayNativeComponentType = HostComponent; export type Overlay = { rect: {left: number, top: number, width: number, height: number}, color: ?ProcessedColorValue, @@ -27,7 +27,7 @@ export type Overlay = { interface NativeCommands { +draw: ( - viewRef: React.ElementRef, + viewRef: React.ElementRef, // TODO(T144046177): Ideally we can pass array of Overlay, but currently // Array type is not supported in RN codegen for building native commands. overlays: string, @@ -39,5 +39,5 @@ export const Commands: NativeCommands = codegenNativeCommands({ }); export default (codegenNativeComponent( - 'TraceUpdateOverlay', + 'DebuggingOverlay', ): HostComponent); diff --git a/packages/react-native/Libraries/Image/Image.android.js b/packages/react-native/Libraries/Image/Image.android.js index 3e63b61e717465..e5c5d9f223b616 100644 --- a/packages/react-native/Libraries/Image/Image.android.js +++ b/packages/react-native/Libraries/Image/Image.android.js @@ -16,7 +16,10 @@ import flattenStyle from '../StyleSheet/flattenStyle'; import StyleSheet from '../StyleSheet/StyleSheet'; import TextAncestor from '../Text/TextAncestor'; import ImageAnalyticsTagContext from './ImageAnalyticsTagContext'; -import {unstable_getImageComponentDecorator} from './ImageInjection'; +import { + unstable_getImageComponentDecorator, + useWrapRefWithImageAttachedCallbacks, +} from './ImageInjection'; import {getImageSourcesFromImageProps} from './ImageSourceUtils'; import {convertObjectFitToResizeMode} from './ImageUtils'; import ImageViewNativeComponent from './ImageViewNativeComponent'; @@ -176,7 +179,6 @@ let BaseImage: AbstractImageAndroid = React.forwardRef( loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri : null, - ref: forwardedRef, accessibilityLabel: props['aria-label'] ?? props.accessibilityLabel ?? props.alt, accessibilityLabelledBy: @@ -197,6 +199,8 @@ let BaseImage: AbstractImageAndroid = React.forwardRef( const resizeMode = objectFit || props.resizeMode || style?.resizeMode || 'cover'; + const actualRef = useWrapRefWithImageAttachedCallbacks(forwardedRef); + return ( {analyticTag => { @@ -218,7 +222,7 @@ let BaseImage: AbstractImageAndroid = React.forwardRef( resizeMode={resizeMode} headers={nativeProps.headers} src={sources} - ref={forwardedRef} + ref={actualRef} /> ); } @@ -227,6 +231,7 @@ let BaseImage: AbstractImageAndroid = React.forwardRef( ); }} diff --git a/packages/react-native/Libraries/Image/Image.ios.js b/packages/react-native/Libraries/Image/Image.ios.js index ea3dcb972aa81d..ce21b5b4edf049 100644 --- a/packages/react-native/Libraries/Image/Image.ios.js +++ b/packages/react-native/Libraries/Image/Image.ios.js @@ -16,7 +16,10 @@ import {createRootTag} from '../ReactNative/RootTag'; import flattenStyle from '../StyleSheet/flattenStyle'; import StyleSheet from '../StyleSheet/StyleSheet'; import ImageAnalyticsTagContext from './ImageAnalyticsTagContext'; -import {unstable_getImageComponentDecorator} from './ImageInjection'; +import { + unstable_getImageComponentDecorator, + useWrapRefWithImageAttachedCallbacks, +} from './ImageInjection'; import {getImageSourcesFromImageProps} from './ImageSourceUtils'; import {convertObjectFitToResizeMode} from './ImageUtils'; import ImageViewNativeComponent from './ImageViewNativeComponent'; @@ -158,6 +161,8 @@ let BaseImage: AbstractImageIOS = React.forwardRef((props, forwardedRef) => { }; const accessibilityLabel = props['aria-label'] ?? props.accessibilityLabel; + const actualRef = useWrapRefWithImageAttachedCallbacks(forwardedRef); + return ( {analyticTag => { @@ -167,7 +172,7 @@ let BaseImage: AbstractImageIOS = React.forwardRef((props, forwardedRef) => { {...restProps} accessible={props.alt !== undefined ? true : props.accessible} accessibilityLabel={accessibilityLabel ?? props.alt} - ref={forwardedRef} + ref={actualRef} style={style} resizeMode={resizeMode} tintColor={tintColor} diff --git a/packages/react-native/Libraries/Image/ImageInjection.js b/packages/react-native/Libraries/Image/ImageInjection.js index 9f4c4b7198349b..072ac69fd35d92 100644 --- a/packages/react-native/Libraries/Image/ImageInjection.js +++ b/packages/react-native/Libraries/Image/ImageInjection.js @@ -8,7 +8,15 @@ * @flow strict-local */ -import type {AbstractImageAndroid, AbstractImageIOS} from './ImageTypes.flow'; +import type { + AbstractImageAndroid, + AbstractImageIOS, + Image as ImageComponent, +} from './ImageTypes.flow'; + +import useMergeRefs from '../Utilities/useMergeRefs'; +import * as React from 'react'; +import {useRef} from 'react'; type ImageComponentDecorator = (AbstractImageAndroid => AbstractImageAndroid) & (AbstractImageIOS => AbstractImageIOS); @@ -24,3 +32,56 @@ export function unstable_setImageComponentDecorator( export function unstable_getImageComponentDecorator(): ?ImageComponentDecorator { return injectedImageComponentDecorator; } + +type ImageInstance = React.ElementRef; + +type ImageAttachedCallback = ( + imageInstance: ImageInstance, +) => void | (() => void); + +const imageAttachedCallbacks = new Set(); + +export function unstable_registerImageAttachedCallback( + callback: ImageAttachedCallback, +): void { + imageAttachedCallbacks.add(callback); +} + +export function unstable_unregisterImageAttachedCallback( + callback: ImageAttachedCallback, +): void { + imageAttachedCallbacks.delete(callback); +} + +export function useWrapRefWithImageAttachedCallbacks( + forwardedRef: React.RefSetter, +): React.RefSetter { + const pendingCleanupCallbacks = useRef void>>([]); + + const imageAttachedCallbacksRef = + useRef void>(null); + + if (imageAttachedCallbacksRef.current == null) { + imageAttachedCallbacksRef.current = (node: ImageInstance | null): void => { + if (node == null) { + if (pendingCleanupCallbacks.current.length > 0) { + pendingCleanupCallbacks.current.forEach(cb => cb()); + pendingCleanupCallbacks.current = []; + } + } else { + imageAttachedCallbacks.forEach(imageAttachedCallback => { + const maybeCleanupCallback = imageAttachedCallback(node); + if (maybeCleanupCallback != null) { + pendingCleanupCallbacks.current.push(maybeCleanupCallback); + } + }); + } + }; + } + + // `useMergeRefs` returns a stable ref if its arguments don't change. + return useMergeRefs( + forwardedRef, + imageAttachedCallbacksRef.current, + ); +} diff --git a/packages/react-native/Libraries/Image/ImageViewNativeComponent.js b/packages/react-native/Libraries/Image/ImageViewNativeComponent.js index bd9ae7df499b25..01459dddc053d1 100644 --- a/packages/react-native/Libraries/Image/ImageViewNativeComponent.js +++ b/packages/react-native/Libraries/Image/ImageViewNativeComponent.js @@ -20,9 +20,11 @@ import type { } from '../StyleSheet/StyleSheet'; import type {ResolvedAssetSource} from './AssetSourceResolver'; import type {ImageProps} from './ImageProps'; +import type {ElementRef} from 'react'; import * as NativeComponentRegistry from '../NativeComponent/NativeComponentRegistry'; import {ConditionallyIgnoredEventHandlers} from '../NativeComponent/ViewConfigIgnore'; +import codegenNativeCommands from '../Utilities/codegenNativeCommands'; import Platform from '../Utilities/Platform'; type Props = $ReadOnly<{ @@ -44,6 +46,17 @@ type Props = $ReadOnly<{ loadingIndicatorSrc?: ?string, }>; +interface NativeCommands { + +setIsVisible_EXPERIMENTAL: ( + viewRef: ElementRef>, + isVisible: boolean, + ) => void; +} + +export const Commands: NativeCommands = codegenNativeCommands({ + supportedCommands: ['setIsVisible_EXPERIMENTAL'], +}); + export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = Platform.OS === 'android' ? { @@ -77,6 +90,11 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = borderTopLeftRadius: true, resizeMethod: true, src: true, + // NOTE: New Architecture expects this to be called `source`, + // regardless of the platform, therefore propagate it as well. + // For the backwards compatibility reasons, we keep both `src` + // and `source`, which will be identical at this stage. + source: true, borderRadius: true, headers: true, shouldNotifyLoadEvents: true, diff --git a/packages/react-native/Libraries/Image/NativeImageLoaderAndroid.js b/packages/react-native/Libraries/Image/NativeImageLoaderAndroid.js index 121de3bc99e3de..8576e47b4e05f6 100644 --- a/packages/react-native/Libraries/Image/NativeImageLoaderAndroid.js +++ b/packages/react-native/Libraries/Image/NativeImageLoaderAndroid.js @@ -12,24 +12,17 @@ import type {TurboModule} from '../TurboModule/RCTExport'; import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; +export type ImageSize = { + width: number, + height: number, + ... +}; + export interface Spec extends TurboModule { +abortRequest: (requestId: number) => void; +getConstants: () => {||}; - +getSize: (uri: string) => Promise< - $ReadOnly<{ - width: number, - height: number, - ... - }>, - >; - +getSizeWithHeaders: ( - uri: string, - headers: Object, - ) => Promise<{ - width: number, - height: number, - ... - }>; + +getSize: (uri: string) => Promise; + +getSizeWithHeaders: (uri: string, headers: Object) => Promise; +prefetchImage: (uri: string, requestId: number) => Promise; +queryCache: (uris: Array) => Promise; } diff --git a/packages/react-native/Libraries/Image/__tests__/Image-test.js b/packages/react-native/Libraries/Image/__tests__/Image-test.js index 6eb4600f191c3c..46124adc88ef2a 100644 --- a/packages/react-native/Libraries/Image/__tests__/Image-test.js +++ b/packages/react-native/Libraries/Image/__tests__/Image-test.js @@ -11,8 +11,13 @@ 'use strict'; +import type {ElementRef} from 'react'; + +import {act, create} from 'react-test-renderer'; + const render = require('../../../jest/renderer'); const Image = require('../Image'); +const ImageInjection = require('../ImageInjection'); const React = require('react'); describe('', () => { @@ -39,4 +44,251 @@ describe('', () => { const instance = render.create(); expect(instance).toMatchSnapshot(); }); + + it('should invoke original ref callbacks correctly when using image attached callbacks', () => { + jest.dontMock('../Image'); + + let imageInstanceFromCallback = null; + let imageInstanceFromRef1 = null; + let imageInstanceFromRef2 = null; + + const callback = jest.fn((instance: ElementRef) => { + imageInstanceFromCallback = instance; + + return () => { + imageInstanceFromCallback = null; + }; + }); + + ImageInjection.unstable_registerImageAttachedCallback(callback); + + expect(imageInstanceFromCallback).toBe(null); + + let testRenderer; + + const ref1 = jest.fn(instance => { + imageInstanceFromRef1 = instance; + }); + + act(() => { + testRenderer = create(); + }); + + expect(imageInstanceFromCallback).not.toBe(null); + expect(imageInstanceFromRef1).not.toBe(null); + expect(imageInstanceFromCallback).toBe(imageInstanceFromRef1); + expect(callback).toHaveBeenCalledTimes(1); + expect(ref1).toHaveBeenCalledTimes(1); + + const ref2 = jest.fn( + (instance: React.ElementRef | null): void => { + imageInstanceFromRef2 = instance; + }, + ); + + act(() => { + testRenderer.update(); + }); + + expect(imageInstanceFromCallback).not.toBe(null); + expect(imageInstanceFromRef1).toBe(null); + expect(imageInstanceFromRef2).not.toBe(null); + expect(imageInstanceFromCallback).toBe(imageInstanceFromRef2); + expect(callback).toHaveBeenCalledTimes(2); + expect(ref1).toHaveBeenCalledTimes(2); + expect(ref2).toHaveBeenCalledTimes(1); + + act(() => { + testRenderer.update(); + }); + + expect(callback).toHaveBeenCalledTimes(2); + expect(ref2).toHaveBeenCalledTimes(1); + }); + + it('should call image attached callbacks (basic)', () => { + jest.dontMock('../Image'); + + let imageInstanceFromCallback = null; + let imageInstanceFromRef = null; + + const callback = (instance: ElementRef) => { + imageInstanceFromCallback = instance; + + return () => { + imageInstanceFromCallback = null; + }; + }; + + ImageInjection.unstable_registerImageAttachedCallback(callback); + + expect(imageInstanceFromCallback).toBe(null); + + let testRenderer; + + act(() => { + testRenderer = create( + { + imageInstanceFromRef = instance; + }} + />, + ); + }); + + expect(imageInstanceFromCallback).not.toBe(null); + expect(imageInstanceFromRef).not.toBe(null); + expect(imageInstanceFromCallback).toBe(imageInstanceFromRef); + + act(() => { + testRenderer.update(<>); + }); + + expect(imageInstanceFromCallback).toBe(null); + expect(imageInstanceFromRef).toBe(null); + + ImageInjection.unstable_unregisterImageAttachedCallback(callback); + + act(() => { + testRenderer.update( + { + imageInstanceFromRef = instance; + }} + />, + ); + }); + + expect(imageInstanceFromRef).not.toBe(null); + expect(imageInstanceFromCallback).toBe(null); + }); + + it('should call image attached callbacks (multiple callbacks)', () => { + jest.dontMock('../Image'); + + let imageInstanceFromCallback1 = null; + let imageInstanceFromCallback2 = null; + let imageInstanceFromRef = null; + + ImageInjection.unstable_registerImageAttachedCallback(instance => { + imageInstanceFromCallback1 = instance; + + return () => { + imageInstanceFromCallback1 = null; + }; + }); + + ImageInjection.unstable_registerImageAttachedCallback(instance => { + imageInstanceFromCallback2 = instance; + + return () => { + imageInstanceFromCallback2 = null; + }; + }); + + expect(imageInstanceFromCallback1).toBe(null); + expect(imageInstanceFromCallback2).toBe(null); + + let testRenderer; + + act(() => { + testRenderer = create( + { + imageInstanceFromRef = instance; + }} + />, + ); + }); + + expect(imageInstanceFromRef).not.toBe(null); + expect(imageInstanceFromCallback1).not.toBe(null); + expect(imageInstanceFromCallback2).not.toBe(null); + expect(imageInstanceFromCallback1).toBe(imageInstanceFromRef); + expect(imageInstanceFromCallback2).toBe(imageInstanceFromRef); + + act(() => { + testRenderer.update(<>); + }); + + expect(imageInstanceFromRef).toBe(null); + expect(imageInstanceFromCallback1).toBe(null); + expect(imageInstanceFromCallback2).toBe(null); + }); + + it('should call image attached callbacks (multiple images)', () => { + jest.dontMock('../Image'); + + let imageInstancesFromCallback = new Set>(); + + ImageInjection.unstable_registerImageAttachedCallback(instance => { + imageInstancesFromCallback.add(instance); + + return () => { + imageInstancesFromCallback.delete(instance); + }; + }); + + expect(imageInstancesFromCallback.size).toBe(0); + + let testRenderer; + + let firstInstance; + let secondInstance; + + const firstImageElement = ( + { + firstInstance = instance; + }} + /> + ); + + const secondImageElement = ( + { + secondInstance = instance; + }} + /> + ); + + act(() => { + testRenderer = create( + <> + {firstImageElement} + {secondImageElement} + , + ); + }); + + expect(firstInstance).not.toBe(null); + expect(secondInstance).not.toBe(null); + expect(imageInstancesFromCallback.size).toBe(2); + expect([...imageInstancesFromCallback][0]).toBe(firstInstance); + expect([...imageInstancesFromCallback][1]).toBe(secondInstance); + + act(() => { + testRenderer.update(<>{secondImageElement}); + }); + + expect(firstInstance).toBe(null); + expect(secondInstance).not.toBe(null); + expect(imageInstancesFromCallback.size).toBe(1); + expect([...imageInstancesFromCallback][0]).toBe(secondInstance); + + act(() => { + testRenderer.update(<>); + }); + + expect(firstInstance).toBe(null); + expect(secondInstance).toBe(null); + expect(imageInstancesFromCallback.size).toBe(0); + }); }); diff --git a/packages/react-native/Libraries/Inspector/Inspector.js b/packages/react-native/Libraries/Inspector/Inspector.js index f22c5457756b5a..dc274521388903 100644 --- a/packages/react-native/Libraries/Inspector/Inspector.js +++ b/packages/react-native/Libraries/Inspector/Inspector.js @@ -16,7 +16,6 @@ import type { } from '../Renderer/shims/ReactNativeTypes'; import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; import type {ReactDevToolsAgent} from '../Types/ReactDevToolsTypes'; -import type {HostRef} from './getInspectorDataForViewAtPoint'; const View = require('../Components/View/View'); const PressabilityDebug = require('../Pressability/PressabilityDebug'); @@ -47,13 +46,13 @@ export type InspectedElement = $ReadOnly<{ export type ElementsHierarchy = InspectorData['hierarchy']; type Props = { - inspectedView: ?HostRef, + inspectedViewRef: React.RefObject | null>, onRequestRerenderApp: () => void, reactDevToolsAgent?: ReactDevToolsAgent, }; function Inspector({ - inspectedView, + inspectedViewRef, onRequestRerenderApp, reactDevToolsAgent, }: Props): React.Node { @@ -126,7 +125,7 @@ function Inspector({ }; getInspectorDataForViewAtPoint( - inspectedView, + inspectedViewRef.current, locationX, locationY, viewData => { diff --git a/packages/react-native/Libraries/Inspector/ReactDevToolsOverlay.js b/packages/react-native/Libraries/Inspector/ReactDevToolsOverlay.js index 04959ca766e6c3..cca9e7e8b7dc88 100644 --- a/packages/react-native/Libraries/Inspector/ReactDevToolsOverlay.js +++ b/packages/react-native/Libraries/Inspector/ReactDevToolsOverlay.js @@ -14,7 +14,6 @@ import type { InstanceFromReactDevTools, ReactDevToolsAgent, } from '../Types/ReactDevToolsTypes'; -import type {HostRef} from './getInspectorDataForViewAtPoint'; import type {InspectedElement} from './Inspector'; import View from '../Components/View/View'; @@ -30,12 +29,12 @@ const getInspectorDataForViewAtPoint = require('./getInspectorDataForViewAtPoint const {useEffect, useState, useCallback} = React; type Props = { - inspectedView: ?HostRef, + inspectedViewRef: React.RefObject | null>, reactDevToolsAgent: ReactDevToolsAgent, }; export default function ReactDevToolsOverlay({ - inspectedView, + inspectedViewRef, reactDevToolsAgent, }: Props): React.Node { const [inspected, setInspected] = useState(null); @@ -125,24 +124,29 @@ export default function ReactDevToolsOverlay({ const findViewForLocation = useCallback( (x: number, y: number) => { - getInspectorDataForViewAtPoint(inspectedView, x, y, viewData => { - const {touchedViewTag, closestInstance, frame} = viewData; - if (closestInstance != null || touchedViewTag != null) { - // We call `selectNode` for both non-fabric(viewTag) and fabric(instance), - // this makes sure it works for both architectures. - reactDevToolsAgent.selectNode(findNodeHandle(touchedViewTag)); - if (closestInstance != null) { - reactDevToolsAgent.selectNode(closestInstance); + getInspectorDataForViewAtPoint( + inspectedViewRef.current, + x, + y, + viewData => { + const {touchedViewTag, closestInstance, frame} = viewData; + if (closestInstance != null || touchedViewTag != null) { + // We call `selectNode` for both non-fabric(viewTag) and fabric(instance), + // this makes sure it works for both architectures. + reactDevToolsAgent.selectNode(findNodeHandle(touchedViewTag)); + if (closestInstance != null) { + reactDevToolsAgent.selectNode(closestInstance); + } + setInspected({ + frame, + }); + return true; } - setInspected({ - frame, - }); - return true; - } - return false; - }); + return false; + }, + ); }, - [inspectedView, reactDevToolsAgent], + [inspectedViewRef, reactDevToolsAgent], ); const stopInspecting = useCallback(() => { diff --git a/packages/react-native/Libraries/IntersectionObserver/NativeIntersectionObserver.h b/packages/react-native/Libraries/IntersectionObserver/NativeIntersectionObserver.h index 20cd6e63db3fa9..1281f60db29fe1 100644 --- a/packages/react-native/Libraries/IntersectionObserver/NativeIntersectionObserver.h +++ b/packages/react-native/Libraries/IntersectionObserver/NativeIntersectionObserver.h @@ -20,7 +20,7 @@ using NativeIntersectionObserverIntersectionObserverId = int32_t; using RectAsTuple = std::tuple; using NativeIntersectionObserverObserveOptions = - NativeIntersectionObserverCxxBaseNativeIntersectionObserverObserveOptions< + NativeIntersectionObserverCxxNativeIntersectionObserverObserveOptions< // intersectionObserverId NativeIntersectionObserverIntersectionObserverId, // targetShadowNode @@ -30,16 +30,11 @@ using NativeIntersectionObserverObserveOptions = template <> struct Bridging - : NativeIntersectionObserverCxxBaseNativeIntersectionObserverObserveOptionsBridging< - // intersectionObserverId - NativeIntersectionObserverIntersectionObserverId, - // targetShadowNode - jsi::Object, - // thresholds - std::vector> {}; + : NativeIntersectionObserverCxxNativeIntersectionObserverObserveOptionsBridging< + NativeIntersectionObserverObserveOptions> {}; using NativeIntersectionObserverEntry = - NativeIntersectionObserverCxxBaseNativeIntersectionObserverEntry< + NativeIntersectionObserverCxxNativeIntersectionObserverEntry< // intersectionObserverId NativeIntersectionObserverIntersectionObserverId, // targetInstanceHandle @@ -57,21 +52,8 @@ using NativeIntersectionObserverEntry = template <> struct Bridging - : NativeIntersectionObserverCxxBaseNativeIntersectionObserverEntryBridging< - // intersectionObserverId - NativeIntersectionObserverIntersectionObserverId, - // targetInstanceHandle - jsi::Value, - // targetRect - RectAsTuple, - // rootRect - RectAsTuple, - // intersectionRect - std::optional, - // isIntersectingAboveThresholds - bool, - // time - double> {}; + : NativeIntersectionObserverCxxNativeIntersectionObserverEntryBridging< + NativeIntersectionObserverEntry> {}; class NativeIntersectionObserver : public NativeIntersectionObserverCxxSpec, diff --git a/packages/react-native/Libraries/MutationObserver/NativeMutationObserver.h b/packages/react-native/Libraries/MutationObserver/NativeMutationObserver.h index cbf7120a49d56a..b7c2eab986d930 100644 --- a/packages/react-native/Libraries/MutationObserver/NativeMutationObserver.h +++ b/packages/react-native/Libraries/MutationObserver/NativeMutationObserver.h @@ -17,7 +17,7 @@ namespace facebook::react { using NativeMutationObserverObserveOptions = - NativeMutationObserverCxxBaseNativeMutationObserverObserveOptions< + NativeMutationObserverCxxNativeMutationObserverObserveOptions< // mutationObserverId MutationObserverId, // targetShadowNode @@ -27,15 +27,10 @@ using NativeMutationObserverObserveOptions = template <> struct Bridging - : NativeMutationObserverCxxBaseNativeMutationObserverObserveOptionsBridging< - // mutationObserverId - MutationObserverId, - // targetShadowNode - jsi::Object, - // subtree - bool> {}; - -using NativeMutationRecord = NativeMutationObserverCxxBaseNativeMutationRecord< + : NativeMutationObserverCxxNativeMutationObserverObserveOptionsBridging< + NativeMutationObserverObserveOptions> {}; + +using NativeMutationRecord = NativeMutationObserverCxxNativeMutationRecord< // mutationObserverId MutationObserverId, // target @@ -47,15 +42,8 @@ using NativeMutationRecord = NativeMutationObserverCxxBaseNativeMutationRecord< template <> struct Bridging - : NativeMutationObserverCxxBaseNativeMutationRecordBridging< - // mutationObserverId - MutationObserverId, - // target - jsi::Value, - // addedNodes - std::vector, - // removedNodes - std::vector> {}; + : NativeMutationObserverCxxNativeMutationRecordBridging< + NativeMutationRecord> {}; class NativeMutationObserver : public NativeMutationObserverCxxSpec, diff --git a/packages/react-native/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm b/packages/react-native/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm index b1b884a097fa37..cdf38d90dcd297 100644 --- a/packages/react-native/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm +++ b/packages/react-native/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm @@ -59,14 +59,6 @@ - (void)invalidate [_surfacePresenter removeObserver:self]; } -- (dispatch_queue_t)methodQueue -{ - // This module needs to be on the same queue as the UIManager to avoid - // having to lock `_operations` and `_preOperations` since `uiManagerWillPerformMounting` - // will be called from that queue. - return RCTGetUIManagerQueue(); -} - /* * In bridgeless mode, `setBridge` is never called during initializtion. Instead this selector is invoked via * BridgelessTurboModuleSetup. @@ -90,32 +82,40 @@ - (void)setSurfacePresenter:(id)surfacePresenter RCT_EXPORT_METHOD(createAnimatedNode : (double)tag config : (NSDictionary *)config) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager createAnimatedNode:[NSNumber numberWithDouble:tag] config:config]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager createAnimatedNode:[NSNumber numberWithDouble:tag] config:config]; + }]; + }); } RCT_EXPORT_METHOD(updateAnimatedNodeConfig : (double)tag config : (NSDictionary *)config) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager updateAnimatedNodeConfig:[NSNumber numberWithDouble:tag] config:config]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager updateAnimatedNodeConfig:[NSNumber numberWithDouble:tag] config:config]; + }]; + }); } RCT_EXPORT_METHOD(connectAnimatedNodes : (double)parentTag childTag : (double)childTag) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager connectAnimatedNodes:[NSNumber numberWithDouble:parentTag] - childTag:[NSNumber numberWithDouble:childTag]]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager connectAnimatedNodes:[NSNumber numberWithDouble:parentTag] + childTag:[NSNumber numberWithDouble:childTag]]; + }]; + }); } RCT_EXPORT_METHOD(disconnectAnimatedNodes : (double)parentTag childTag : (double)childTag) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager disconnectAnimatedNodes:[NSNumber numberWithDouble:parentTag] - childTag:[NSNumber numberWithDouble:childTag]]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager disconnectAnimatedNodes:[NSNumber numberWithDouble:parentTag] + childTag:[NSNumber numberWithDouble:childTag]]; + }]; + }); } RCT_EXPORT_METHOD(startAnimatingNode @@ -124,101 +124,126 @@ - (void)setSurfacePresenter:(id)surfacePresenter : (NSDictionary *)config endCallback : (RCTResponseSenderBlock)callBack) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager startAnimatingNode:[NSNumber numberWithDouble:animationId] - nodeTag:[NSNumber numberWithDouble:nodeTag] - config:config - endCallback:callBack]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager startAnimatingNode:[NSNumber numberWithDouble:animationId] + nodeTag:[NSNumber numberWithDouble:nodeTag] + config:config + endCallback:callBack]; + }]; - [self flushOperationQueues]; + [self flushOperationQueues]; + }); } RCT_EXPORT_METHOD(stopAnimation : (double)animationId) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager stopAnimation:[NSNumber numberWithDouble:animationId]]; - }]; - [self flushOperationQueues]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager stopAnimation:[NSNumber numberWithDouble:animationId]]; + }]; + [self flushOperationQueues]; + }); } RCT_EXPORT_METHOD(setAnimatedNodeValue : (double)nodeTag value : (double)value) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager setAnimatedNodeValue:[NSNumber numberWithDouble:nodeTag] value:[NSNumber numberWithDouble:value]]; - }]; - // In Bridge, flushing of native animations is done from RCTCxxBridge batchDidComplete(). - // Since RCTCxxBridge doesn't exist in Bridgeless, and components are not remounted in Fabric for native animations, - // flush here for changes in Animated.Value for Animated.event. - [self flushOperationQueues]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager setAnimatedNodeValue:[NSNumber numberWithDouble:nodeTag] value:[NSNumber numberWithDouble:value]]; + }]; + // In Bridge, flushing of native animations is done from RCTCxxBridge batchDidComplete(). + // Since RCTCxxBridge doesn't exist in Bridgeless, and components are not remounted in Fabric for native animations, + // flush here for changes in Animated.Value for Animated.event. + [self flushOperationQueues]; + }); } RCT_EXPORT_METHOD(setAnimatedNodeOffset : (double)nodeTag offset : (double)offset) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager setAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag] offset:[NSNumber numberWithDouble:offset]]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager setAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag] + offset:[NSNumber numberWithDouble:offset]]; + }]; + }); } RCT_EXPORT_METHOD(flattenAnimatedNodeOffset : (double)nodeTag) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager flattenAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag]]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager flattenAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag]]; + }]; + }); } RCT_EXPORT_METHOD(extractAnimatedNodeOffset : (double)nodeTag) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager extractAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag]]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager extractAnimatedNodeOffset:[NSNumber numberWithDouble:nodeTag]]; + }]; + }); } RCT_EXPORT_METHOD(connectAnimatedNodeToView : (double)nodeTag viewTag : (double)viewTag) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - // viewName is not used when node is managed by Fabric, and nodes are always managed by Fabric in Bridgeless. - [nodesManager connectAnimatedNodeToView:[NSNumber numberWithDouble:nodeTag] - viewTag:[NSNumber numberWithDouble:viewTag] - viewName:nil]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + // viewName is not used when node is managed by Fabric, and nodes are always managed by Fabric in Bridgeless. + [nodesManager connectAnimatedNodeToView:[NSNumber numberWithDouble:nodeTag] + viewTag:[NSNumber numberWithDouble:viewTag] + viewName:nil]; + }]; + }); } RCT_EXPORT_METHOD(disconnectAnimatedNodeFromView : (double)nodeTag viewTag : (double)viewTag) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager disconnectAnimatedNodeFromView:[NSNumber numberWithDouble:nodeTag] - viewTag:[NSNumber numberWithDouble:viewTag]]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager disconnectAnimatedNodeFromView:[NSNumber numberWithDouble:nodeTag] + viewTag:[NSNumber numberWithDouble:viewTag]]; + }]; + }); } RCT_EXPORT_METHOD(restoreDefaultValues : (double)nodeTag) { - [self addPreOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager restoreDefaultValues:[NSNumber numberWithDouble:nodeTag]]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addPreOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager restoreDefaultValues:[NSNumber numberWithDouble:nodeTag]]; + }]; + }); } RCT_EXPORT_METHOD(dropAnimatedNode : (double)tag) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager dropAnimatedNode:[NSNumber numberWithDouble:tag]]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager dropAnimatedNode:[NSNumber numberWithDouble:tag]]; + }]; + }); } RCT_EXPORT_METHOD(startListeningToAnimatedNodeValue : (double)tag) { - __weak id valueObserver = self; - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager startListeningToAnimatedNodeValue:[NSNumber numberWithDouble:tag] valueObserver:valueObserver]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + __weak id valueObserver = self; + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager startListeningToAnimatedNodeValue:[NSNumber numberWithDouble:tag] valueObserver:valueObserver]; + }]; + }); } RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue : (double)tag) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager stopListeningToAnimatedNodeValue:[NSNumber numberWithDouble:tag]]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager stopListeningToAnimatedNodeValue:[NSNumber numberWithDouble:tag]]; + }]; + }); } RCT_EXPORT_METHOD(addAnimatedEventToView @@ -233,11 +258,13 @@ - (void)setSurfacePresenter:(id)surfacePresenter eventMappingDict[@"animatedValueTag"] = @(*eventMapping.animatedValueTag()); } - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager addAnimatedEventToView:[NSNumber numberWithDouble:viewTag] - eventName:eventName - eventMapping:eventMappingDict]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager addAnimatedEventToView:[NSNumber numberWithDouble:viewTag] + eventName:eventName + eventMapping:eventMappingDict]; + }]; + }); } RCT_EXPORT_METHOD(removeAnimatedEventFromView @@ -245,18 +272,22 @@ - (void)setSurfacePresenter:(id)surfacePresenter : (nonnull NSString *)eventName animatedNodeTag : (double)animatedNodeTag) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager removeAnimatedEventFromView:[NSNumber numberWithDouble:viewTag] - eventName:eventName - animatedNodeTag:[NSNumber numberWithDouble:animatedNodeTag]]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager removeAnimatedEventFromView:[NSNumber numberWithDouble:viewTag] + eventName:eventName + animatedNodeTag:[NSNumber numberWithDouble:animatedNodeTag]]; + }]; + }); } RCT_EXPORT_METHOD(getValue : (double)nodeTag saveValueCallback : (RCTResponseSenderBlock)saveValueCallback) { - [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { - [nodesManager getValue:[NSNumber numberWithDouble:nodeTag] saveCallback:saveValueCallback]; - }]; + dispatch_async(RCTGetUIManagerQueue(), ^{ + [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { + [nodesManager getValue:[NSNumber numberWithDouble:nodeTag] saveCallback:saveValueCallback]; + }]; + }); } RCT_EXPORT_METHOD(queueAndExecuteBatchedOperations : (NSArray *)operationsAndArgs) diff --git a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js index 0326ec9afd621d..a077a2b1f5f3b2 100644 --- a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js +++ b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js @@ -304,6 +304,7 @@ const validAttributesForEventProps = { onTouchCancel: true, // Pointer events + onClick: true, onPointerEnter: true, onPointerEnterCapture: true, onPointerLeave: true, diff --git a/packages/react-native/Libraries/ReactNative/AppContainer-dev.js b/packages/react-native/Libraries/ReactNative/AppContainer-dev.js index 4e7f2c43e6b077..3e4fe8389610e7 100644 --- a/packages/react-native/Libraries/ReactNative/AppContainer-dev.js +++ b/packages/react-native/Libraries/ReactNative/AppContainer-dev.js @@ -18,7 +18,6 @@ import type {Props} from './AppContainer'; import TraceUpdateOverlay from '../Components/TraceUpdateOverlay/TraceUpdateOverlay'; import ReactNativeStyleAttributes from '../Components/View/ReactNativeStyleAttributes'; import View from '../Components/View/View'; -import ViewNativeComponent from '../Components/View/ViewNativeComponent'; import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter'; import ReactDevToolsOverlay from '../Inspector/ReactDevToolsOverlay'; import LogBoxNotificationContainer from '../LogBox/LogBoxNotificationContainer'; @@ -41,13 +40,13 @@ if (reactDevToolsHook) { } type InspectorDeferredProps = { - inspectedView: React.ElementRef | null, + inspectedViewRef: React.RefObject | null>, onInspectedViewRerenderRequest: () => void, reactDevToolsAgent?: ReactDevToolsAgent, }; const InspectorDeferred = ({ - inspectedView, + inspectedViewRef, onInspectedViewRerenderRequest, reactDevToolsAgent, }: InspectorDeferredProps) => { @@ -57,7 +56,7 @@ const InspectorDeferred = ({ return ( @@ -74,9 +73,7 @@ const AppContainer = ({ showArchitectureIndicator, WrapperComponent, }: Props): React.Node => { - const [mainRef, setMainRef] = useState | null>(null); + const innerViewRef = React.useRef | null>(null); const [key, setKey] = useState(0); const [shouldRenderInspector, setShouldRenderInspector] = useState(false); @@ -118,7 +115,7 @@ const AppContainer = ({ pointerEvents="box-none" key={key} style={styles.container} - ref={setMainRef}> + ref={innerViewRef}> {children} ); @@ -149,14 +146,14 @@ const AppContainer = ({ )} {reactDevToolsAgent != null && ( )} {shouldRenderInspector && ( diff --git a/packages/react-native/Libraries/Utilities/useMergeRefs.js b/packages/react-native/Libraries/Utilities/useMergeRefs.js index 15bd982d036896..1499e4eab3afdb 100644 --- a/packages/react-native/Libraries/Utilities/useMergeRefs.js +++ b/packages/react-native/Libraries/Utilities/useMergeRefs.js @@ -8,13 +8,9 @@ * @format */ +import * as React from 'react'; import {useCallback} from 'react'; -type CallbackRef = T => mixed; -type ObjectRef = {current: T, ...}; - -type Ref = CallbackRef | ObjectRef; - /** * Constructs a new ref that forwards new values to each of the given refs. The * given refs will always be invoked in the order that they are supplied. @@ -24,11 +20,11 @@ type Ref = CallbackRef | ObjectRef; * the returned callback ref is supplied as a `ref` to a React element, this may * lead to problems with the given refs being invoked more times than desired. */ -export default function useMergeRefs( - ...refs: $ReadOnlyArray> -): CallbackRef { +export default function useMergeRefs( + ...refs: $ReadOnlyArray> +): (Instance | null) => void { return useCallback( - (current: T) => { + (current: Instance | null) => { for (const ref of refs) { if (ref != null) { if (typeof ref === 'function') { diff --git a/packages/react-native/Libraries/WebPerformance/NativePerformanceObserver.h b/packages/react-native/Libraries/WebPerformance/NativePerformanceObserver.h index bc55f2476d2132..c5e7c3cc4b8ec4 100644 --- a/packages/react-native/Libraries/WebPerformance/NativePerformanceObserver.h +++ b/packages/react-native/Libraries/WebPerformance/NativePerformanceObserver.h @@ -20,7 +20,7 @@ class PerformanceEntryReporter; using RawPerformanceEntryType = int32_t; -using RawPerformanceEntry = NativePerformanceObserverCxxBaseRawPerformanceEntry< +using RawPerformanceEntry = NativePerformanceObserverCxxRawPerformanceEntry< std::string, RawPerformanceEntryType, double, @@ -32,25 +32,18 @@ using RawPerformanceEntry = NativePerformanceObserverCxxBaseRawPerformanceEntry< template <> struct Bridging - : NativePerformanceObserverCxxBaseRawPerformanceEntryBridging< - std::string, - RawPerformanceEntryType, - double, - double, - std::optional, - std::optional, - std::optional> {}; + : NativePerformanceObserverCxxRawPerformanceEntryBridging< + RawPerformanceEntry> {}; using GetPendingEntriesResult = - NativePerformanceObserverCxxBaseGetPendingEntriesResult< + NativePerformanceObserverCxxGetPendingEntriesResult< std::vector, uint32_t>; template <> struct Bridging - : NativePerformanceObserverCxxBaseGetPendingEntriesResultBridging< - std::vector, - uint32_t> {}; + : NativePerformanceObserverCxxGetPendingEntriesResultBridging< + GetPendingEntriesResult> {}; #pragma mark - implementation diff --git a/packages/react-native/React-Core.podspec b/packages/react-native/React-Core.podspec index da75b42c0ac996..e2b1ed82b7622b 100644 --- a/packages/react-native/React-Core.podspec +++ b/packages/react-native/React-Core.podspec @@ -22,6 +22,7 @@ socket_rocket_version = '0.7.0' boost_compiler_flags = '-Wno-documentation' use_hermes = ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == '1' +use_hermes_flag = use_hermes ? "-DUSE_HERMES=1" : "" header_subspecs = { 'CoreModulesHeaders' => 'React/CoreModules/**/*.h', @@ -63,7 +64,7 @@ Pod::Spec.new do |s| s.platforms = min_supported_versions s.source = source s.resource_bundle = { "RCTI18nStrings" => ["React/I18n/strings/*.lproj"]} - s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags + s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags + ' ' + use_hermes_flag s.header_dir = "React" s.framework = "JavaScriptCore" s.pod_target_xcconfig = { @@ -129,6 +130,8 @@ Pod::Spec.new do |s| s.dependency "Yoga" s.dependency "glog" + add_dependency(s, "RCTDeprecation") + if use_hermes s.dependency 'React-hermes' s.dependency 'hermes-engine' diff --git a/packages/react-native/React/Base/RCTBridgeModule.h b/packages/react-native/React/Base/RCTBridgeModule.h index 15d871fa76a7cd..a43b0b4fccfe93 100644 --- a/packages/react-native/React/Base/RCTBridgeModule.h +++ b/packages/react-native/React/Base/RCTBridgeModule.h @@ -11,6 +11,8 @@ #import #import +#import + #import "RCTBundleManager.h" @class RCTBridge; @@ -146,7 +148,7 @@ RCT_EXTERN_C_END * To implement this in your module, just add `@synthesize bridge = _bridge;` * If using Swift, add `@objc var bridge: RCTBridge!` to your module. */ -@property (nonatomic, weak, readonly) RCTBridge *bridge; +@property (nonatomic, weak, readonly) RCTBridge *bridge RCT_DEPRECATED; /** * The queue that will be used to call all exported methods. If omitted, this diff --git a/packages/react-native/React/CoreModules/RCTActionSheetManager.mm b/packages/react-native/React/CoreModules/RCTActionSheetManager.mm index dbe389a1eced46..f8df74b2401604 100644 --- a/packages/react-native/React/CoreModules/RCTActionSheetManager.mm +++ b/packages/react-native/React/CoreModules/RCTActionSheetManager.mm @@ -100,9 +100,9 @@ - (void)presentViewController:(UIViewController *)alertController [RCTConvert UIColor:options.cancelButtonTintColor() ? @(*options.cancelButtonTintColor()) : nil]; NSString *userInterfaceStyle = [RCTConvert NSString:options.userInterfaceStyle()]; - UIViewController *controller = RCTPresentedViewController(); - dispatch_async(dispatch_get_main_queue(), ^{ + UIViewController *controller = RCTPresentedViewController(); + if (controller == nil) { RCTLogError( @"Tried to display action sheet but there is no application window. options: %@", @{ diff --git a/packages/react-native/React/CoreModules/RCTDevMenu.mm b/packages/react-native/React/CoreModules/RCTDevMenu.mm index 10b218a3f632e7..1a970a7d086952 100644 --- a/packages/react-native/React/CoreModules/RCTDevMenu.mm +++ b/packages/react-native/React/CoreModules/RCTDevMenu.mm @@ -283,8 +283,7 @@ - (void)setDefaultJSBundle [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString * { - return devSettings.isElementInspectorShown ? @"Hide Element Inspector" - : @"Show Element Inspector"; + return @"Toggle Element Inspector"; } handler:^{ [devSettings toggleElementInspector]; diff --git a/packages/react-native/React/CxxBridge/RCTCxxBridge.mm b/packages/react-native/React/CxxBridge/RCTCxxBridge.mm index af931fd45ca10f..03aa3d0654c2a8 100644 --- a/packages/react-native/React/CxxBridge/RCTCxxBridge.mm +++ b/packages/react-native/React/CxxBridge/RCTCxxBridge.mm @@ -41,15 +41,7 @@ #import #import -#ifndef RCT_USE_HERMES -#if __has_include() -#define RCT_USE_HERMES 1 -#else -#define RCT_USE_HERMES 0 -#endif -#endif - -#if RCT_USE_HERMES +#if USE_HERMES #import #else #import "JSCExecutorFactory.h" @@ -423,7 +415,7 @@ - (void)start } if (!executorFactory) { auto installBindings = RCTJSIExecutorRuntimeInstaller(nullptr); -#if RCT_USE_HERMES +#if USE_HERMES executorFactory = std::make_shared(installBindings); #else executorFactory = std::make_shared(installBindings); diff --git a/packages/react-native/React/FBReactNativeSpec/FBReactNativeSpec.podspec b/packages/react-native/React/FBReactNativeSpec/FBReactNativeSpec.podspec deleted file mode 100644 index 4480a83562a479..00000000000000 --- a/packages/react-native/React/FBReactNativeSpec/FBReactNativeSpec.podspec +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -require "json" - -react_native_path = "../.." -require_relative "#{react_native_path}/scripts/react_native_pods.rb" - -package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json"))) -version = package['version'] - -source = { :git => 'https://github.com/facebook/react-native.git' } -if version == '1000.0.0' - # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. - source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1") -else - source[:tag] = "v#{version}" -end - -folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_CFG_NO_COROUTINES=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -Wno-comma -Wno-shorten-64-to-32' -folly_version = '2023.08.07.00' - -Pod::Spec.new do |s| - s.name = "FBReactNativeSpec" - s.version = version - s.summary = "-" # TODO - s.homepage = "https://reactnative.dev/" - s.license = package["license"] - s.author = "Meta Platforms, Inc. and its affiliates" - s.platforms = min_supported_versions - s.compiler_flags = folly_compiler_flags + ' -Wno-nullability-completeness' - s.source = source - # This podspec is used to trigger the codegen, and built files are generated in a different location. - # We don't want this pod to actually include any files. - s.header_dir = "FBReactNativeSpec" - - s.pod_target_xcconfig = { - "USE_HEADERMAP" => "YES", - "CLANG_CXX_LANGUAGE_STANDARD" => "c++20", - "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/RCT-Folly\"" - } - - s.dependency "RCT-Folly", folly_version - s.dependency "RCTRequired", version - s.dependency "RCTTypeSafety", version - s.dependency "React-Core", version - s.dependency "React-jsi", version - s.dependency "ReactCommon/turbomodule/core", version - - use_react_native_codegen!(s, { - :react_native_path => react_native_path, - :js_srcs_dir => "#{react_native_path}/Libraries", - :library_name => "FBReactNativeSpec", - :library_type => "modules", - }) -end diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm index 09b6b70700a27a..4d0c75f282ee5d 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm @@ -41,7 +41,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); + const auto &defaultProps = ActivityIndicatorViewShadowNode::defaultSharedProps(); _props = defaultProps; _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithFrame:self.bounds]; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/DebuggingOverlay/RCTDebuggingOverlayComponentView.h b/packages/react-native/React/Fabric/Mounting/ComponentViews/DebuggingOverlay/RCTDebuggingOverlayComponentView.h new file mode 100644 index 00000000000000..9ee08512265621 --- /dev/null +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/DebuggingOverlay/RCTDebuggingOverlayComponentView.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +#import + +@interface RCTDebuggingOverlayComponentView : RCTViewComponentView + +@end diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/DebuggingOverlay/RCTDebuggingOverlayComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/DebuggingOverlay/RCTDebuggingOverlayComponentView.mm new file mode 100644 index 00000000000000..c9ac90286f9c4c --- /dev/null +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/DebuggingOverlay/RCTDebuggingOverlayComponentView.mm @@ -0,0 +1,63 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTDebuggingOverlayComponentView.h" + +#import +#import +#import + +#import +#import +#import +#import + +#import "RCTFabricComponentsPlugins.h" + +using namespace facebook::react; + +@implementation RCTDebuggingOverlayComponentView { + RCTDebuggingOverlay *_overlay; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + _props = DebuggingOverlayShadowNode::defaultSharedProps(); + _overlay = [[RCTDebuggingOverlay alloc] initWithFrame:self.bounds]; + + self.contentView = _overlay; + } + + return self; +} + +#pragma mark - RCTComponentViewProtocol + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + +#pragma mark - Native commands + +- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args +{ + RCTDebuggingOverlayHandleCommand(self, commandName, args); +} + +- (void)draw:(NSString *)overlays +{ + [_overlay draw:overlays]; +} + +@end + +Class RCTDebuggingOverlayCls(void) +{ + return RCTDebuggingOverlayComponentView.class; +} diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm index e48d5470179e4f..2de560d78f74b3 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm @@ -28,7 +28,7 @@ @implementation RCTImageComponentView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); + const auto &defaultProps = ImageShadowNode::defaultSharedProps(); _props = defaultProps; _imageView = [RCTUIImageViewAnimated new]; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm index 454c3ff1ac279d..6ace11ce5ab012 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm @@ -50,8 +50,7 @@ @implementation RCTInputAccessoryComponentView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = InputAccessoryShadowNode::defaultSharedProps(); _contentView = [RCTInputAccessoryContentView new]; _touchHandler = [RCTSurfaceTouchHandler new]; [_touchHandler attachToView:_contentView]; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm index 42fa691dfebd55..86aee3223d7659 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm @@ -31,8 +31,7 @@ @implementation RCTLegacyViewManagerInteropComponentView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = LegacyViewManagerInteropShadowNode::defaultSharedProps(); _viewsToBeMounted = [NSMutableArray new]; _viewsToBeUnmounted = [NSMutableArray new]; _hasInvokedForwardingWarning = NO; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm index 445a5c79a5afaf..e20eee608a01c6 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm @@ -110,8 +110,7 @@ @implementation RCTModalHostViewComponentView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = ModalHostViewShadowNode::defaultSharedProps(); _shouldAnimatePresentation = YES; _isPresented = NO; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h index ca5f395c3141a8..54936a93de7c5c 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h @@ -31,6 +31,7 @@ Class RCTFabricComponentsProvider(const char *name); // Lookup functions Class RCTActivityIndicatorViewCls(void) __attribute__((used)); +Class RCTDebuggingOverlayCls(void) __attribute__((used)); Class RCTInputAccessoryCls(void) __attribute__((used)); Class RCTParagraphCls(void) __attribute__((used)); Class RCTPullToRefreshViewCls(void) __attribute__((used)); diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm index 02d1dc1a125af7..f07b0301cd28a5 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm @@ -19,6 +19,7 @@ Class RCTFabricComponentsProvider(const char *name) { static std::unordered_map sFabricComponentsClassMap = { {"ActivityIndicatorView", RCTActivityIndicatorViewCls}, + {"DebuggingOverlay", RCTDebuggingOverlayCls}, {"InputAccessoryView", RCTInputAccessoryCls}, {"Paragraph", RCTParagraphCls}, {"PullToRefreshView", RCTPullToRefreshViewCls}, diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.mm index 4efa8b34b4a7a0..eb81a151c3fc41 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.mm @@ -18,8 +18,7 @@ @implementation RCTRootComponentView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = RootShadowNode::defaultSharedProps(); } return self; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm index 4c9060f1a622fd..709e378ad49d83 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm @@ -22,8 +22,7 @@ @implementation RCTSafeAreaViewComponentView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = SafeAreaViewShadowNode::defaultSharedProps(); } return self; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.mm index 231777cd48950a..64b09228a397e5 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.mm @@ -36,8 +36,7 @@ - (instancetype)initWithFrame:(CGRect)frame // The pull-to-refresh view is not a subview of this view. self.hidden = YES; - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = PullToRefreshViewShadowNode::defaultSharedProps(); _refreshControl = [UIRefreshControl new]; [_refreshControl addTarget:self diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index 504b0ef147ae0b..41e5ebc3cf1a35 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -118,8 +118,7 @@ + (RCTScrollViewComponentView *_Nullable)findScrollViewComponentViewForView:(UIV - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = ScrollViewShadowNode::defaultSharedProps(); _scrollView = [[RCTEnhancedScrollView alloc] initWithFrame:self.bounds]; _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; @@ -134,11 +133,7 @@ - (instancetype)initWithFrame:(CGRect)frame [self.scrollViewDelegateSplitter addDelegate:self]; - if (CoreFeatures::disableScrollEventThrottleRequirement) { - _scrollEventThrottle = 0; - } else { - _scrollEventThrottle = INFINITY; - } + _scrollEventThrottle = 0; } return self; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm index d4ed3860e474c7..941ad9b7f0978e 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm @@ -29,8 +29,7 @@ @implementation RCTSwitchComponentView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = SwitchShadowNode::defaultSharedProps(); _switchView = [[UISwitch alloc] initWithFrame:self.bounds]; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm index fce427848a9c11..0787ef71cafe8e 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm @@ -40,8 +40,7 @@ @implementation RCTParagraphComponentView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = ParagraphShadowNode::defaultSharedProps(); self.opaque = NO; self.contentMode = UIViewContentModeRedraw; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index e7b69bff2f9e68..44e74da5cea06f 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -62,11 +62,10 @@ @implementation RCTTextInputComponentView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); + const auto &defaultProps = TextInputShadowNode::defaultSharedProps(); _props = defaultProps; - auto &props = *defaultProps; - _backedTextInputView = props.traits.multiline ? [RCTUITextView new] : [RCTUITextField new]; + _backedTextInputView = defaultProps->traits.multiline ? [RCTUITextView new] : [RCTUITextField new]; _backedTextInputView.textInputDelegate = self; _ignoreNextTextInputCall = NO; _comingFromJS = NO; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/UnimplementedComponent/RCTUnimplementedNativeComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/UnimplementedComponent/RCTUnimplementedNativeComponentView.mm index fc39e2592de4d0..fe4c9f6a65b142 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/UnimplementedComponent/RCTUnimplementedNativeComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/UnimplementedComponent/RCTUnimplementedNativeComponentView.mm @@ -20,8 +20,7 @@ @implementation RCTUnimplementedNativeComponentView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = UnimplementedNativeViewShadowNode::defaultSharedProps(); CGRect bounds = self.bounds; _label = [[UILabel alloc] initWithFrame:bounds]; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/UnimplementedView/RCTUnimplementedViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/UnimplementedView/RCTUnimplementedViewComponentView.mm index 6a9efe577fb045..b5185677875a13 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/UnimplementedView/RCTUnimplementedViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/UnimplementedView/RCTUnimplementedViewComponentView.mm @@ -27,8 +27,7 @@ @implementation RCTUnimplementedViewComponentView { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = UnimplementedViewShadowNode::defaultSharedProps(); _label = [[UILabel alloc] initWithFrame:self.bounds]; _label.backgroundColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.3]; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 9fa696f7a49a72..6751018c889162 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -46,8 +46,7 @@ + (void)load - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; + _props = ViewShadowNode::defaultSharedProps(); _reactSubviews = [NSMutableArray new]; self.multipleTouchEnabled = YES; } diff --git a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm index df069c0865553b..da9a026dafefd8 100644 --- a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm +++ b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm @@ -276,10 +276,6 @@ - (RCTScheduler *)_createScheduler CoreFeatures::enableMountHooks = true; } - if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:disable_scroll_event_throttle_requirement")) { - CoreFeatures::disableScrollEventThrottleRequirement = true; - } - if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:enable_default_async_batched_priority")) { CoreFeatures::enableDefaultAsyncBatchedPriority = true; } @@ -288,6 +284,10 @@ - (RCTScheduler *)_createScheduler CoreFeatures::enableClonelessStateProgression = true; } + if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:position_relative_default")) { + CoreFeatures::positionRelativeDefault = true; + } + auto componentRegistryFactory = [factory = wrapManagedObject(_mountingManager.componentViewRegistry.componentViewFactory)]( const EventDispatcher::Weak &eventDispatcher, const ContextContainer::Shared &contextContainer) { diff --git a/packages/react-native/React/Inspector/RCTInspectorPackagerConnection.m b/packages/react-native/React/Inspector/RCTInspectorPackagerConnection.m index ae28f4c7fa5476..07b1b404b5b1bb 100644 --- a/packages/react-native/React/Inspector/RCTInspectorPackagerConnection.m +++ b/packages/react-native/React/Inspector/RCTInspectorPackagerConnection.m @@ -28,7 +28,6 @@ @interface RCTInspectorPackagerConnection () { NSURL *_url; NSMutableDictionary *_inspectorConnections; SRWebSocket *_webSocket; - dispatch_queue_t _jsQueue; BOOL _closed; BOOL _suppressConnectionErrors; RCTBundleStatusProvider _bundleStatusProvider; @@ -57,7 +56,6 @@ - (instancetype)initWithURL:(NSURL *)url if (self = [super init]) { _url = url; _inspectorConnections = [NSMutableDictionary new]; - _jsQueue = dispatch_queue_create("com.facebook.react.WebSocketExecutor", DISPATCH_QUEUE_SERIAL); } return self; } @@ -247,7 +245,6 @@ - (void)connect // timeouts, but our previous class, RCTSRWebSocket didn't have the same // implemented options. Might be worth reinvestigating for SRWebSocket? _webSocket = [[SRWebSocket alloc] initWithURL:_url]; - [_webSocket setDelegateDispatchQueue:_jsQueue]; _webSocket.delegate = self; [_webSocket open]; } @@ -282,7 +279,7 @@ - (void)closeQuietly - (void)sendToPackager:(NSDictionary *)messageObject { __weak RCTInspectorPackagerConnection *weakSelf = self; - dispatch_async(_jsQueue, ^{ + dispatch_async(dispatch_get_main_queue(), ^{ RCTInspectorPackagerConnection *strongSelf = weakSelf; if (strongSelf && !strongSelf->_closed) { NSError *error; diff --git a/packages/react-native/React/React-RCTFabric.podspec b/packages/react-native/React/React-RCTFabric.podspec index 5c2f3c62fd80f4..9e7b934711d76f 100644 --- a/packages/react-native/React/React-RCTFabric.podspec +++ b/packages/react-native/React/React-RCTFabric.podspec @@ -58,7 +58,7 @@ Pod::Spec.new do |s| s.framework = ["JavaScriptCore", "MobileCoreServices"] s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => header_search_paths, - "OTHER_CFLAGS" => "$(inherited) -DRN_FABRIC_ENABLED" + " " + folly_flags, + "OTHER_CFLAGS" => "$(inherited) " + folly_flags, "CLANG_CXX_LANGUAGE_STANDARD" => "c++20" }.merge!(ENV['USE_FRAMEWORKS'] != nil ? { "PUBLIC_HEADERS_FOLDER_PATH" => "#{module_name}.framework/Headers/#{header_dir}" @@ -75,7 +75,7 @@ Pod::Spec.new do |s| add_dependency(s, "React-FabricImage") add_dependency(s, "React-Fabric", :additional_framework_paths => [ "react/renderer/textlayoutmanager/platform/ios", - "react/renderer/components/textinput/iostextinput", + "react/renderer/components/textinput/platform/ios", "react/renderer/components/view/platform/cxx", "react/renderer/imagemanager/platform/ios", ]) diff --git a/packages/react-native/React/Tests/Text/RCTParagraphComponentViewTests.mm b/packages/react-native/React/Tests/Text/RCTParagraphComponentViewTests.mm index da306ba8092441..f23f353e121288 100644 --- a/packages/react-native/React/Tests/Text/RCTParagraphComponentViewTests.mm +++ b/packages/react-native/React/Tests/Text/RCTParagraphComponentViewTests.mm @@ -121,8 +121,8 @@ - (void)setUp auto &props = *sharedProps; props.layoutConstraints = LayoutConstraints{{0, 0}, {500, 500}}; auto &yogaStyle = props.yogaStyle; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(200)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(200)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(200)); return sharedProps; }) .children({ @@ -133,11 +133,11 @@ - (void)setUp auto &props = *sharedProps; props.accessible = true; auto &yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Absolute; - yogaStyle.position()[YGEdgeLeft] = YGValue{0, YGUnitPoint}; - yogaStyle.position()[YGEdgeTop] = YGValue{0, YGUnitPoint}; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(200)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(200)); + yogaStyle.setPositionType(yoga::PositionType::Absolute); + yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(0)); + yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(0)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(200)); return sharedProps; }) .children({ @@ -213,11 +213,11 @@ - (void)setUp auto &props = *sharedProps; props.accessible = true; auto &yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Absolute; - yogaStyle.position()[YGEdgeLeft] = YGValue{0, YGUnitPoint}; - yogaStyle.position()[YGEdgeTop] = YGValue{30, YGUnitPoint}; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(200)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(50)); + yogaStyle.setPositionType(yoga::PositionType::Absolute); + yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(0)); + yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(30)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(50)); return sharedProps; }) .children({ @@ -257,11 +257,11 @@ - (void)setUp auto &props = *sharedProps; props.accessible = true; auto &yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Absolute; - yogaStyle.position()[YGEdgeLeft] = YGValue{0, YGUnitPoint}; - yogaStyle.position()[YGEdgeTop] = YGValue{90, YGUnitPoint}; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(200)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(50)); + yogaStyle.setPositionType(yoga::PositionType::Absolute); + yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(0)); + yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(90)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(50)); return sharedProps; }) .children({ @@ -418,8 +418,8 @@ - (void)testEntireParagraphLink auto &props = *sharedProps; props.layoutConstraints = LayoutConstraints{{0, 0}, {500, 500}}; auto &yogaStyle = props.yogaStyle; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(200)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(200)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(200)); return sharedProps; }) .children({ @@ -431,11 +431,11 @@ - (void)testEntireParagraphLink props.accessible = true; props.accessibilityTraits = AccessibilityTraits::Link; auto &yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Absolute; - yogaStyle.position()[YGEdgeLeft] = YGValue{0, YGUnitPoint}; - yogaStyle.position()[YGEdgeTop] = YGValue{0, YGUnitPoint}; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(200)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(20)); + yogaStyle.setPositionType(yoga::PositionType::Absolute); + yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(0)); + yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(90)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(20)); return sharedProps; }) .children({ diff --git a/packages/react-native/React/Views/RCTDebuggingOverlay.h b/packages/react-native/React/Views/RCTDebuggingOverlay.h new file mode 100644 index 00000000000000..64b7d1feb03e45 --- /dev/null +++ b/packages/react-native/React/Views/RCTDebuggingOverlay.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +@interface RCTDebuggingOverlay : RCTView + +- (void)draw:(NSString *)serializedNodes; + +@end diff --git a/packages/react-native/React/Views/RCTDebuggingOverlay.m b/packages/react-native/React/Views/RCTDebuggingOverlay.m new file mode 100644 index 00000000000000..992862bd5ec2f0 --- /dev/null +++ b/packages/react-native/React/Views/RCTDebuggingOverlay.m @@ -0,0 +1,57 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTDebuggingOverlay.h" + +#import +#import +#import + +@implementation RCTDebuggingOverlay + +- (void)draw:(NSString *)serializedNodes +{ + NSArray *subViewsToRemove = [self subviews]; + for (UIView *v in subViewsToRemove) { + [v removeFromSuperview]; + } + + NSError *error = nil; + id deserializedNodes = RCTJSONParse(serializedNodes, &error); + + if (error) { + RCTLogError(@"Failed to parse serialized nodes passed to RCTDebuggingOverlay"); + return; + } + + if (![deserializedNodes isKindOfClass:[NSArray class]]) { + RCTLogError(@"Expected to receive nodes as an array, got %@", NSStringFromClass([deserializedNodes class])); + return; + } + + for (NSDictionary *node in deserializedNodes) { + NSDictionary *nodeRectangle = node[@"rect"]; + NSNumber *nodeColor = node[@"color"]; + + NSNumber *x = nodeRectangle[@"left"]; + NSNumber *y = nodeRectangle[@"top"]; + NSNumber *width = nodeRectangle[@"width"]; + NSNumber *height = nodeRectangle[@"height"]; + + CGRect rect = CGRectMake(x.doubleValue, y.doubleValue, width.doubleValue, height.doubleValue); + + UIView *box = [[UIView alloc] initWithFrame:rect]; + box.backgroundColor = [UIColor clearColor]; + + box.layer.borderWidth = 2.0f; + box.layer.borderColor = [RCTConvert UIColor:nodeColor].CGColor; + + [self addSubview:box]; + } +} + +@end diff --git a/packages/react-native/React/Views/RCTDebuggingOverlayManager.h b/packages/react-native/React/Views/RCTDebuggingOverlayManager.h new file mode 100644 index 00000000000000..a852cc81883e19 --- /dev/null +++ b/packages/react-native/React/Views/RCTDebuggingOverlayManager.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@interface RCTDebuggingOverlayManager : RCTViewManager + +@end diff --git a/packages/react-native/React/Views/RCTDebuggingOverlayManager.m b/packages/react-native/React/Views/RCTDebuggingOverlayManager.m new file mode 100644 index 00000000000000..ae00c27ac2e23a --- /dev/null +++ b/packages/react-native/React/Views/RCTDebuggingOverlayManager.m @@ -0,0 +1,38 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTDebuggingOverlayManager.h" +#import "RCTDebuggingOverlay.h" + +#import +#import + +#import "RCTBridge.h" + +@implementation RCTDebuggingOverlayManager + +RCT_EXPORT_MODULE(DebuggingOverlay) + +- (UIView *)view +{ + return [RCTDebuggingOverlay new]; +} + +RCT_EXPORT_METHOD(draw : (nonnull NSNumber *)viewTag nodes : (NSString *)serializedNodes) +{ + [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + UIView *view = viewRegistry[viewTag]; + + if ([view isKindOfClass:[RCTDebuggingOverlay class]]) { + [(RCTDebuggingOverlay *)view draw:serializedNodes]; + } else { + RCTLogError(@"Expected view to be RCTDebuggingOverlay, got %@", NSStringFromClass([view class])); + } + }]; +} + +@end diff --git a/packages/react-native/React/Views/RCTView.m b/packages/react-native/React/Views/RCTView.m index bb8336615a0208..6e6f9cd2761035 100644 --- a/packages/react-native/React/Views/RCTView.m +++ b/packages/react-native/React/Views/RCTView.m @@ -883,7 +883,7 @@ static void RCTUpdateShadowPathForView(RCTView *view) RCTLogAdvice( @"View #%@ of type %@ has a shadow set but cannot calculate " - "shadow efficiently. Consider setting a background color to " + "shadow efficiently. Consider setting a solid background color to " "fix this, or apply the shadow to a more specific component.", view.reactTag, [view class]); diff --git a/packages/react-native/React/Views/SafeAreaView/RCTSafeAreaView.m b/packages/react-native/React/Views/SafeAreaView/RCTSafeAreaView.m index 41dc74b06b66be..eeb12da71bfb41 100644 --- a/packages/react-native/React/Views/SafeAreaView/RCTSafeAreaView.m +++ b/packages/react-native/React/Views/SafeAreaView/RCTSafeAreaView.m @@ -57,7 +57,12 @@ - (void)safeAreaInsetsDidChange - (void)setSafeAreaInsets:(UIEdgeInsets)safeAreaInsets { - if (UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale())) { + // Relayout with different padding may result in a close but slightly different result, amplified by Yoga rounding to + // physical pixel grid. To avoid infinite relayout, allow one physical pixel of difference, along with small amount of + // extra tolerance for FP error. + CGFloat tolerance = 1.0 / RCTScreenScale() + 0.01; + + if (UIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, tolerance)) { return; } diff --git a/packages/react-native/React/Views/ScrollView/RCTScrollView.m b/packages/react-native/React/Views/ScrollView/RCTScrollView.m index 98b7f14533b081..3ad69069ef15d9 100644 --- a/packages/react-native/React/Views/ScrollView/RCTScrollView.m +++ b/packages/react-native/React/Views/ScrollView/RCTScrollView.m @@ -674,8 +674,7 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView * We limit the delta to 17ms so that small throttles intended to enable 60fps updates will not * inadvertently filter out any scroll events. */ - if (_allowNextScrollNoMatterWhat || - (_scrollEventThrottle > 0 && _scrollEventThrottle < MAX(0.017, now - _lastScrollDispatchTime))) { + if (_allowNextScrollNoMatterWhat || (_scrollEventThrottle < MAX(0.017, now - _lastScrollDispatchTime))) { RCT_SEND_SCROLL_EVENT(onScroll, nil); // Update dispatch time _lastScrollDispatchTime = now; diff --git a/packages/react-native/ReactAndroid/build.gradle b/packages/react-native/ReactAndroid/build.gradle index ebf4cf3c26dc67..3dbd23de72c928 100644 --- a/packages/react-native/ReactAndroid/build.gradle +++ b/packages/react-native/ReactAndroid/build.gradle @@ -105,6 +105,10 @@ final def preparePrefab = tasks.register("preparePrefab", PreparePrefabHeadersTa "react_newarchdefaults", new Pair("src/main/jni/react/newarchdefaults", "") ), + new PrefabPreprocessingEntry( + "react_cxxreactpackage", + new Pair("src/main/jni/react/runtime/cxxreactpackage", "") + ), new PrefabPreprocessingEntry( "react_render_animations", new Pair("../ReactCommon/react/renderer/animations/", "react/renderer/animations/") @@ -530,6 +534,7 @@ android { "react_utils", "react_render_componentregistry", "react_newarchdefaults", + "react_cxxreactpackage", "react_render_animations", "react_render_core", "react_render_graphics", @@ -650,6 +655,9 @@ android { react_newarchdefaults { headers(new File(prefabHeadersDir, "react_newarchdefaults").absolutePath) } + react_cxxreactpackage { + headers(new File(prefabHeadersDir, "react_cxxreactpackage").absolutePath) + } react_render_animations { headers(new File(prefabHeadersDir, "react_render_animations").absolutePath) } diff --git a/packages/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake b/packages/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake index d49fa9ed80d80b..964e76f3753cf0 100644 --- a/packages/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake +++ b/packages/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake @@ -71,6 +71,7 @@ add_library(react_debug ALIAS ReactAndroid::react_debug) add_library(react_utils ALIAS ReactAndroid::react_utils) add_library(react_render_componentregistry ALIAS ReactAndroid::react_render_componentregistry) add_library(react_newarchdefaults ALIAS ReactAndroid::react_newarchdefaults) +add_library(react_cxxreactpackage ALIAS ReactAndroid::react_cxxreactpackage) add_library(react_render_core ALIAS ReactAndroid::react_render_core) add_library(react_render_graphics ALIAS ReactAndroid::react_render_graphics) add_library(rrc_view ALIAS ReactAndroid::rrc_view) @@ -99,6 +100,7 @@ target_link_libraries(${CMAKE_PROJECT_NAME} react_utils # prefab ready react_nativemodule_core # prefab ready react_newarchdefaults # prefab ready + react_cxxreactpackage # prefab ready react_render_componentregistry # prefab ready react_render_core # prefab ready react_render_debug # prefab ready diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java index 0168fce4f5ba7f..69471937ab8501 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java @@ -19,7 +19,7 @@ import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.ViewManager; -import com.facebook.react.views.traceupdateoverlay.TraceUpdateOverlayManager; +import com.facebook.react.views.debuggingoverlay.DebuggingOverlayManager; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -43,13 +43,12 @@ class DebugCorePackage extends TurboReactPackage implements ViewManagerOnDemandR public DebugCorePackage() {} @Override - public NativeModule getModule(String name, ReactApplicationContext reactContext) { + public @Nullable NativeModule getModule(String name, ReactApplicationContext reactContext) { switch (name) { case JSCHeapCapture.NAME: return new JSCHeapCapture(reactContext); default: - throw new IllegalArgumentException( - "In DebugCorePackage, could not find Native module for " + name); + return null; } } @@ -97,8 +96,7 @@ private static void appendMap( private Map getViewManagersMap() { if (mViewManagers == null) { Map viewManagers = new HashMap<>(); - appendMap( - viewManagers, TraceUpdateOverlayManager.REACT_CLASS, TraceUpdateOverlayManager::new); + appendMap(viewManagers, DebuggingOverlayManager.REACT_CLASS, DebuggingOverlayManager::new); mViewManagers = viewManagers; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/LazyTurboModuleManagerDelegate.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/LazyTurboModuleManagerDelegate.java deleted file mode 100644 index be7c47f1611330..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/LazyTurboModuleManagerDelegate.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react; - -import androidx.annotation.Nullable; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.common.annotations.UnstableReactNativeAPI; -import com.facebook.react.internal.turbomodule.core.interfaces.TurboModule; -import java.util.List; - -/** - * This abstract class provides a simple Lazy implementation of TurboModuleManagerDelegate. Main - * difference between this class and ReactPackageTurboModuleManagerDelegate is that - * LazyTurboModuleManagerDelegate does not require NativeModules to be annotated using a - * ReactModule, also this class does not use the {@link - * TurboReactPackage#getReactModuleInfoProvider} method. This class is for experimentation purposes - * only, not to meant to be used in production. - */ -@UnstableReactNativeAPI -public abstract class LazyTurboModuleManagerDelegate - extends ReactPackageTurboModuleManagerDelegate { - - private final List mPackages; - private final ReactApplicationContext mReactContext; - - public LazyTurboModuleManagerDelegate( - ReactApplicationContext reactApplicationContext, List packages) { - super(); - mPackages = packages; - mReactContext = reactApplicationContext; - } - - @Override - @Nullable - public TurboModule getModule(String moduleName) { - /* - * Returns first TurboModule found with the name received as a parameter. There's no - * warning or error if there are more than one TurboModule registered with the same name in - * different packages. This method relies on the order of insertion of ReactPackage into - * mPackages. Usually the size of mPackages is very small (2 or 3 packages in the majority of - * the cases) - */ - for (ReactPackage reactPackage : mPackages) { - if (reactPackage instanceof BaseReactPackage) { - BaseReactPackage baseReactPackage = (BaseReactPackage) reactPackage; - try { - TurboModule nativeModule = - (TurboModule) baseReactPackage.getModule(moduleName, mReactContext); - if (nativeModule != null) { - return nativeModule; - } - } catch (IllegalArgumentException ex) { - /* - TurboReactPackages can throw an IllegalArgumentException when a module isn't found. If - this happens, it's safe to ignore the exception because a later TurboReactPackage could - provide the module. - */ - } - } else { - throw new IllegalArgumentException("ReactPackage must be an instance of TurboReactPackage"); - } - } - return null; - } - - @Override - public boolean unstable_isModuleRegistered(String moduleName) { - throw new UnsupportedOperationException("unstable_isModuleRegistered is not supported"); - } - - @Override - public boolean unstable_isLazyTurboModuleDelegate() { - return true; - } - - @Override - public boolean unstable_shouldEnableLegacyModuleInterop() { - return false; - } - - @Override - public boolean unstable_shouldRouteTurboModulesThroughLegacyModuleInterop() { - return false; - } - - @Override - public NativeModule getLegacyModule(String moduleName) { - throw new UnsupportedOperationException("Legacy Modules are not supported"); - } - - @Override - public boolean unstable_isLegacyModuleRegistered(String moduleName) { - return false; - }; -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 2ae69e229714bb..4bf3fbbfca982e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -387,7 +387,7 @@ public void handleCxxError(Exception e) { mDevSupportManager.handleException(e); } - public void registerCxxErrorHandlerFunc() { + private void registerCxxErrorHandlerFunc() { Class[] parameterTypes = new Class[1]; parameterTypes[0] = Exception.class; Method handleCxxErrorFunc = null; @@ -399,6 +399,10 @@ public void registerCxxErrorHandlerFunc() { ReactCxxErrorHandler.setHandleErrorFunc(this, handleCxxErrorFunc); } + private void unregisterCxxErrorHandlerFunc() { + ReactCxxErrorHandler.setHandleErrorFunc(null, null); + } + static void initializeSoLoaderIfNecessary(Context applicationContext) { // Call SoLoader.initialize here, this is required for apps that does not use exopackage and // does not use SoLoader for loading other native code except from the one used by React Native @@ -747,23 +751,22 @@ public void destroy() { } moveToBeforeCreateLifecycleState(); - - if (mCreateReactContextThread != null) { - mCreateReactContextThread = null; - } - mMemoryPressureRouter.destroy(mApplicationContext); + unregisterCxxErrorHandlerFunc(); + mCreateReactContextThread = null; synchronized (mReactContextLock) { if (mCurrentReactContext != null) { mCurrentReactContext.destroy(); mCurrentReactContext = null; } } + mHasStartedCreatingInitialContext = false; mCurrentActivity = null; ResourceDrawableIdHelper.getInstance().clear(); + mHasStartedDestroying = false; synchronized (mHasStartedDestroying) { mHasStartedDestroying.notifyAll(); @@ -1296,14 +1299,12 @@ private void detachRootViewFromInstance(ReactRoot reactRoot, ReactContext reactC uiManager.stopSurface(surfaceId); } else { FLog.w(ReactConstants.TAG, "Failed to stop surface, UIManager has already gone away"); - reactRoot.getRootViewGroup().removeAllViews(); } } else { ReactSoftExceptionLogger.logSoftException( TAG, new RuntimeException( "detachRootViewFromInstance called with ReactRootView with invalid id")); - reactRoot.getRootViewGroup().removeAllViews(); } } else { reactContext @@ -1312,8 +1313,7 @@ private void detachRootViewFromInstance(ReactRoot reactRoot, ReactContext reactC .unmountApplicationComponentAtRootTag(reactRoot.getRootViewTag()); } - // The view is no longer attached, so mark it as such by resetting its ID. - reactRoot.getRootViewGroup().setId(View.NO_ID); + clearReactRoot(reactRoot); } @ThreadConfined(UI) @@ -1407,9 +1407,12 @@ private ReactApplicationContext createReactContext( reactContext, catalystInstance.getJavaScriptContextHolder())); } if (ReactFeatureFlags.enableFabricRenderer) { - catalystInstance.getJSIModule(JSIModuleType.UIManager); if (mUIManagerProvider != null) { - catalystInstance.setFabricUIManager(mUIManagerProvider.createUIManager(reactContext)); + UIManager uiManager = mUIManagerProvider.createUIManager(reactContext); + uiManager.initialize(); + catalystInstance.setFabricUIManager(uiManager); + } else { + catalystInstance.getJSIModule(JSIModuleType.UIManager); } } if (mBridgeIdleDebugListener != null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java index 3f1fb6f9462045..5352d11ea9b14e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java @@ -132,7 +132,7 @@ protected final Application getApplication() { } protected @Nullable UIManagerProvider getUIManagerProvider() { - return reactApplicationContext -> null; + return null; } /** Returns whether or not to treat it as normal if Activity is null. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.java index 50b1c6fd32043a..949276ec20b195 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.java @@ -8,11 +8,14 @@ package com.facebook.react; import androidx.annotation.Nullable; +import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; +import com.facebook.jni.HybridData; import com.facebook.react.bridge.CxxModuleWrapper; import com.facebook.react.bridge.ModuleSpec; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.common.ReactConstants; import com.facebook.react.config.ReactFeatureFlags; import com.facebook.react.internal.turbomodule.core.TurboModuleManagerDelegate; import com.facebook.react.internal.turbomodule.core.interfaces.TurboModule; @@ -45,13 +48,34 @@ interface ModuleProvider { private final boolean mEnableTurboModuleSyncVoidMethods = ReactFeatureFlags.unstable_enableTurboModuleSyncVoidMethods; - protected ReactPackageTurboModuleManagerDelegate() { + private final boolean mIsLazy = ReactFeatureFlags.enableTurboModuleStableAPI; + + // Lazy Props + private List mPackages; + private ReactApplicationContext mReactContext; + + protected ReactPackageTurboModuleManagerDelegate( + ReactApplicationContext reactApplicationContext, List packages) { super(); + initialize(reactApplicationContext, packages); } protected ReactPackageTurboModuleManagerDelegate( + ReactApplicationContext reactApplicationContext, + List packages, + HybridData hybridData) { + super(hybridData); + initialize(reactApplicationContext, packages); + } + + private void initialize( ReactApplicationContext reactApplicationContext, List packages) { - super(); + if (mIsLazy) { + mPackages = packages; + mReactContext = reactApplicationContext; + return; + } + final ReactApplicationContext applicationContext = reactApplicationContext; for (ReactPackage reactPackage : packages) { if (reactPackage instanceof BaseReactPackage) { @@ -130,21 +154,66 @@ protected ReactPackageTurboModuleManagerDelegate( @Override public boolean unstable_shouldEnableLegacyModuleInterop() { + if (mIsLazy) { + return false; + } + return mShouldEnableLegacyModuleInterop; } @Override public boolean unstable_shouldRouteTurboModulesThroughLegacyModuleInterop() { + if (mIsLazy) { + return false; + } + return mShouldRouteTurboModulesThroughLegacyModuleInterop; } public boolean unstable_enableSyncVoidMethods() { + if (mIsLazy) { + return false; + } + return mEnableTurboModuleSyncVoidMethods; } @Nullable @Override public TurboModule getModule(String moduleName) { + if (mIsLazy) { + /* + * Returns first TurboModule found with the name received as a parameter. There's no + * warning or error if there are more than one TurboModule registered with the same name in + * different packages. This method relies on the order of insertion of ReactPackage into + * mPackages. Usually the size of mPackages is very small (2 or 3 packages in the majority of + * the cases) + */ + for (ReactPackage reactPackage : mPackages) { + if (reactPackage instanceof BaseReactPackage) { + BaseReactPackage baseReactPackage = (BaseReactPackage) reactPackage; + try { + TurboModule nativeModule = + (TurboModule) baseReactPackage.getModule(moduleName, mReactContext); + if (nativeModule != null) { + return nativeModule; + } + } catch (IllegalArgumentException ex) { + // TODO T170570617: remove this catch statement and let exception bubble up + FLog.e( + ReactConstants.TAG, + ex, + "Caught exception while constructing module '%s'. This was previously ignored but will not be caught in the future.", + moduleName); + } + } else { + throw new IllegalArgumentException( + "ReactPackage must be an instance of TurboReactPackage"); + } + } + return null; + } + NativeModule resolvedModule = null; for (final ModuleProvider moduleProvider : mModuleProviders) { @@ -161,11 +230,12 @@ public TurboModule getModule(String moduleName) { } } catch (IllegalArgumentException ex) { - /* - TurboReactPackages can throw an IllegalArgumentException when a module isn't found. If - this happens, it's safe to ignore the exception because a later TurboReactPackage could - provide the module. - */ + // TODO T170570617: remove this catch statement and let exception bubble up + FLog.e( + ReactConstants.TAG, + ex, + "Caught exception while constructing module '%s'. This was previously ignored but will not be caught in the future.", + moduleName); } } @@ -180,11 +250,15 @@ public TurboModule getModule(String moduleName) { @Override public boolean unstable_isLazyTurboModuleDelegate() { - return false; + return mIsLazy; } @Override public boolean unstable_isModuleRegistered(String moduleName) { + if (mIsLazy) { + throw new UnsupportedOperationException("unstable_isModuleRegistered is not supported"); + } + for (final ModuleProvider moduleProvider : mModuleProviders) { final ReactModuleInfo moduleInfo = mPackageModuleInfos.get(moduleProvider).get(moduleName); if (moduleInfo != null && moduleInfo.isTurboModule()) { @@ -196,6 +270,10 @@ public boolean unstable_isModuleRegistered(String moduleName) { @Override public boolean unstable_isLegacyModuleRegistered(String moduleName) { + if (mIsLazy) { + return false; + } + for (final ModuleProvider moduleProvider : mModuleProviders) { final ReactModuleInfo moduleInfo = mPackageModuleInfos.get(moduleProvider).get(moduleName); if (moduleInfo != null && !moduleInfo.isTurboModule()) { @@ -208,6 +286,10 @@ public boolean unstable_isLegacyModuleRegistered(String moduleName) { @Nullable @Override public NativeModule getLegacyModule(String moduleName) { + if (mIsLazy) { + throw new UnsupportedOperationException("Legacy Modules are not supported"); + } + if (!unstable_shouldEnableLegacyModuleInterop()) { return null; } @@ -226,13 +308,13 @@ public NativeModule getLegacyModule(String moduleName) { resolvedModule = module; } } - } catch (IllegalArgumentException ex) { - /* - * TurboReactPackages can throw an IllegalArgumentException when a module isn't found. If - * this happens, it's safe to ignore the exception because a later TurboReactPackage could - * provide the module. - */ + // TODO T170570617: remove this catch statement and let exception bubble up + FLog.e( + ReactConstants.TAG, + ex, + "Caught exception while constructing module '%s'. This was previously ignored but will not be caught in the future.", + moduleName); } } @@ -247,6 +329,11 @@ public NativeModule getLegacyModule(String moduleName) { @Override public List getEagerInitModuleNames() { + if (mIsLazy) { + throw new UnsupportedOperationException( + "Running delegate in lazy mode. Please override getEagerInitModuleNames() and return a list of module names that need to be initialized eagerly."); + } + List moduleNames = new ArrayList<>(); for (final ModuleProvider moduleProvider : mModuleProviders) { for (final ReactModuleInfo moduleInfo : mPackageModuleInfos.get(moduleProvider).values()) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index be3c61b6dc3622..621372533b22e6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -11,7 +11,6 @@ import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE; import android.content.res.AssetManager; -import android.os.AsyncTask; import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; @@ -374,30 +373,24 @@ public void destroy() { mTurboModuleRegistry.invalidate(); } - getReactQueueConfiguration() - .getUIQueueThread() - .runOnQueue( + // Kill non-UI threads from neutral third party + // potentially expensive, so don't run on UI thread + new Thread( () -> { - // AsyncTask.execute must be executed from the UI Thread - AsyncTask.execute( - () -> { - // Kill non-UI threads from neutral third party - // potentially expensive, so don't run on UI thread - - // contextHolder is used as a lock to guard against - // other users of the JS VM having the VM destroyed - // underneath them, so notify them before we reset - // Native - mJavaScriptContextHolder.clear(); - - mHybridData.resetNative(); - getReactQueueConfiguration().destroy(); - FLog.d( - ReactConstants.TAG, "CatalystInstanceImpl.destroy() end"); - ReactMarker.logMarker( - ReactMarkerConstants.DESTROY_CATALYST_INSTANCE_END); - }); - }); + // contextHolder is used as a lock to guard against + // other users of the JS VM having the VM destroyed + // underneath them, so notify them before we reset + // Native + mJavaScriptContextHolder.clear(); + + mHybridData.resetNative(); + getReactQueueConfiguration().destroy(); + FLog.w(ReactConstants.TAG, "CatalystInstanceImpl.destroy() end"); + ReactMarker.logMarker( + ReactMarkerConstants.DESTROY_CATALYST_INSTANCE_END); + }, + "destroy_react_context") + .start(); }); }); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ModuleHolder.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ModuleHolder.java index 731aa04fa3cf1b..25f170f1134a92 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ModuleHolder.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ModuleHolder.java @@ -19,6 +19,7 @@ import com.facebook.debug.tags.ReactDebugOverlayTags; import com.facebook.infer.annotation.Assertions; import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.common.ReactConstants; import com.facebook.react.internal.turbomodule.core.interfaces.TurboModule; import com.facebook.react.module.model.ReactModuleInfo; import com.facebook.systrace.SystraceMessage; @@ -204,7 +205,7 @@ private NativeModule create() { * * @todo(T53311351) */ - FLog.e("NativeModuleInitError", "Failed to create NativeModule \"" + getName() + "\"", ex); + FLog.e(ReactConstants.TAG, ex, "Failed to create NativeModule '%s'", mName); throw ex; } finally { ReactMarker.logMarker(CREATE_MODULE_END, mName, mInstanceKey); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java index b57513cb67216e..f1f1c83dffc681 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java @@ -26,6 +26,7 @@ import com.facebook.react.bridge.queue.ReactQueueConfiguration; import com.facebook.react.common.LifecycleState; import com.facebook.react.common.ReactConstants; +import com.facebook.react.common.annotations.DeprecatedInNewArchitecture; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.concurrent.CopyOnWriteArraySet; @@ -554,6 +555,21 @@ public boolean isBridgeless() { return mCatalystInstance.getJSIModule(moduleType); } + @DeprecatedInNewArchitecture( + message = + "This method will be deprecated later as part of Stable APIs with bridge removal and not encouraged usage.") + /** + * Get the UIManager for Fabric from the CatalystInstance. + * + * @return The UIManager when CatalystInstance is active. + */ + public @Nullable UIManager getFabricUIManager() { + UIManager uiManager = mCatalystInstance.getFabricUIManager(); + return uiManager != null + ? uiManager + : (UIManager) mCatalystInstance.getJSIModule(JSIModuleType.UIManager); + } + /** * Get the sourceURL for the JS bundle from the CatalystInstance. This method is needed for * compatibility with bridgeless mode, which has no CatalystInstance. diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java index 318c71a597dc55..74de7150a139c8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java @@ -46,8 +46,6 @@ public enum ReactMarkerConstants { CREATE_I18N_MODULE_CONSTANTS_END, I18N_MODULE_CONSTANTS_CONVERT_START, I18N_MODULE_CONSTANTS_CONVERT_END, - CREATE_I18N_ASSETS_MODULE_START, - CREATE_I18N_ASSETS_MODULE_END, GET_CONSTANTS_START, GET_CONSTANTS_END, INITIALIZE_MODULE_START, diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java index c85b7802a8c40e..ea1b2ba963749b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -72,7 +72,7 @@ public class ReactFeatureFlags { public static volatile boolean enableBridgelessArchitectureSoftExceptions = false; /** Does the bridgeless architecture use the new create/reload/destroy routines */ - public static volatile boolean enableBridgelessArchitectureNewCreateReloadDestroy = false; + public static volatile boolean enableBridgelessArchitectureNewCreateReloadDestroy = true; /** This feature flag enables logs for Fabric */ public static boolean enableFabricLogs = false; @@ -182,4 +182,7 @@ public class ReactFeatureFlags { * when there is work to do. */ public static boolean enableOnDemandReactChoreographer = false; + + /** When enabled, the default value of the position style property is relative. */ + public static boolean positionRelativeDefault = false; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultComponentsRegistry.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultComponentsRegistry.kt index 131804140ee901..2cf0b6908e4936 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultComponentsRegistry.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultComponentsRegistry.kt @@ -27,6 +27,10 @@ private constructor(componentFactory: ComponentFactory) { @DoNotStrip private external fun initHybrid(componentFactory: ComponentFactory): HybridData + init { + DefaultSoLoader.maybeLoadSoLibrary() + } + companion object { @JvmStatic @DoNotStrip diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt index fa6ff875dda211..a17f1279deece8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt @@ -8,7 +8,6 @@ package com.facebook.react.defaults import com.facebook.react.config.ReactFeatureFlags -import com.facebook.soloader.SoLoader /** * A utility class that serves as an entry point for users setup the New Architecture. @@ -27,8 +26,7 @@ object DefaultNewArchitectureEntryPoint { fun load( turboModulesEnabled: Boolean = true, fabricEnabled: Boolean = true, - bridgelessEnabled: Boolean = false, - dynamicLibraryName: String = "appmodules", + bridgelessEnabled: Boolean = false ) { ReactFeatureFlags.useTurboModules = turboModulesEnabled ReactFeatureFlags.enableFabricRenderer = fabricEnabled @@ -42,23 +40,21 @@ object DefaultNewArchitectureEntryPoint { this.privateConcurrentReactEnabled = fabricEnabled this.privateBridgelessEnabled = bridgelessEnabled - SoLoader.loadLibrary("react_newarchdefaults") - SoLoader.loadLibrary(dynamicLibraryName) + DefaultSoLoader.maybeLoadSoLibrary() } @Deprecated( message = "Calling DefaultNewArchitectureEntryPoint.load() with different fabricEnabled and concurrentReactEnabled is deprecated. Please use a single flag for both Fabric and Concurrent React", - replaceWith = ReplaceWith("load(turboModulesEnabled, fabricEnabled, dynamicLibraryName)"), + replaceWith = ReplaceWith("load(turboModulesEnabled, fabricEnabled, bridgelessEnabled)"), level = DeprecationLevel.WARNING) fun load( turboModulesEnabled: Boolean = true, fabricEnabled: Boolean = true, bridgelessEnabled: Boolean = false, @Suppress("UNUSED_PARAMETER") concurrentReactEnabled: Boolean = true, - dynamicLibraryName: String = "appmodules", ) { - load(turboModulesEnabled, fabricEnabled, bridgelessEnabled, dynamicLibraryName) + load(turboModulesEnabled, fabricEnabled, bridgelessEnabled) } private var privateFabricEnabled: Boolean = false diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHost.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHost.kt index d481e33c0bd1d9..9a102597199dc1 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHost.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHost.kt @@ -54,13 +54,13 @@ object DefaultReactHost { if (reactHost == null) { val jsBundleLoader = JSBundleLoader.createAssetLoader(context, "assets://$jsBundleAssetPath", true) - val jsEngineInstance = if (isHermesEnabled) HermesInstance() else JSCInstance() + val jsRuntimeFactory = if (isHermesEnabled) HermesInstance() else JSCInstance() val defaultReactHostDelegate = DefaultReactHostDelegate( jsMainModulePath = jsMainModulePath, jsBundleLoader = jsBundleLoader, reactPackages = packageList, - jsEngineInstance = jsEngineInstance, + jsRuntimeFactory = jsRuntimeFactory, turboModuleManagerDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder()) val reactJsExceptionHandler = ReactJsExceptionHandler { _ -> } val componentFactory = ComponentFactory() diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHostDelegate.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHostDelegate.kt index 7221334217754f..40529ef869842e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHostDelegate.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHostDelegate.kt @@ -14,7 +14,7 @@ import com.facebook.react.bridge.JSBundleLoader import com.facebook.react.common.annotations.UnstableReactNativeAPI import com.facebook.react.fabric.ReactNativeConfig import com.facebook.react.runtime.BindingsInstaller -import com.facebook.react.runtime.JSEngineInstance +import com.facebook.react.runtime.JSRuntimeFactory import com.facebook.react.runtime.ReactHostDelegate import com.facebook.react.runtime.hermes.HermesInstance @@ -28,7 +28,7 @@ import com.facebook.react.runtime.hermes.HermesInstance * @param jsBundleLoader Bundle loader to use when setting up JS environment.

Example: * [JSBundleLoader.createFileLoader(application, bundleFile)] * @param reactPackages list of reactPackages to expose Native Modules and View Components to JS - * @param jsEngineInstance Object that holds a native reference to the javascript engine + * @param jsRuntimeFactory Object that holds a native reference to the JS Runtime factory * @param bindingsInstaller Object that holds a native C++ references that allow host applications * to install C++ objects into jsi::Runtime during the initialization of React Native * @param reactNativeConfig ReactNative Configuration that allows to customize the behavior of @@ -42,7 +42,7 @@ class DefaultReactHostDelegate( override val jsMainModulePath: String, override val jsBundleLoader: JSBundleLoader, override val reactPackages: List = emptyList(), - override val jsEngineInstance: JSEngineInstance = HermesInstance(), + override val jsRuntimeFactory: JSRuntimeFactory = HermesInstance(), override val bindingsInstaller: BindingsInstaller = DefaultBindingsInstaller(), private val reactNativeConfig: ReactNativeConfig = ReactNativeConfig.DEFAULT_CONFIG, private val exceptionHandler: (Exception) -> Unit = {}, diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactNativeHost.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactNativeHost.kt index 60c1e791912b42..e5683059a68bdb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactNativeHost.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactNativeHost.kt @@ -14,12 +14,8 @@ import com.facebook.react.ReactHost import com.facebook.react.ReactInstanceManager import com.facebook.react.ReactNativeHost import com.facebook.react.ReactPackageTurboModuleManagerDelegate -import com.facebook.react.bridge.JSIModulePackage -import com.facebook.react.bridge.JSIModuleProvider -import com.facebook.react.bridge.JSIModuleSpec -import com.facebook.react.bridge.JSIModuleType import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.UIManager +import com.facebook.react.bridge.UIManagerProvider import com.facebook.react.fabric.ComponentFactory import com.facebook.react.fabric.FabricUIManagerProviderImpl import com.facebook.react.fabric.ReactNativeConfig @@ -46,30 +42,20 @@ protected constructor( null } - override fun getJSIModulePackage(): JSIModulePackage? = + override fun getUIManagerProvider(): UIManagerProvider? = if (isNewArchEnabled) { - JSIModulePackage { reactApplicationContext: ReactApplicationContext, _ -> - listOf( - object : JSIModuleSpec { - override fun getJSIModuleType(): JSIModuleType = JSIModuleType.UIManager + UIManagerProvider { reactApplicationContext: ReactApplicationContext -> + val componentFactory = ComponentFactory() - override fun getJSIModuleProvider(): JSIModuleProvider { - val componentFactory = ComponentFactory() + DefaultComponentsRegistry.register(componentFactory) - DefaultComponentsRegistry.register(componentFactory) + val reactInstanceManager: ReactInstanceManager = getReactInstanceManager() - val reactInstanceManager: ReactInstanceManager = getReactInstanceManager() - - val viewManagers = - reactInstanceManager.getOrCreateViewManagers(reactApplicationContext) - val viewManagerRegistry = ViewManagerRegistry(viewManagers) - return FabricUIManagerProviderImpl( - reactApplicationContext, - componentFactory, - ReactNativeConfig.DEFAULT_CONFIG, - viewManagerRegistry) - } - }) + val viewManagers = reactInstanceManager.getOrCreateViewManagers(reactApplicationContext) + val viewManagerRegistry = ViewManagerRegistry(viewManagers) + FabricUIManagerProviderImpl( + componentFactory, ReactNativeConfig.DEFAULT_CONFIG, viewManagerRegistry) + .createUIManager(reactApplicationContext) } } else { null diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultSoLoader.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultSoLoader.kt new file mode 100644 index 00000000000000..cebdc7c93234fa --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultSoLoader.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.defaults + +import com.facebook.soloader.SoLoader + +internal class DefaultSoLoader { + companion object { + @Synchronized + @JvmStatic + fun maybeLoadSoLibrary() { + SoLoader.loadLibrary("react_newarchdefaults") + try { + SoLoader.loadLibrary("appmodules") + } catch (e: UnsatisfiedLinkError) { + // ignore: DefaultTurboModuleManagerDelegate is still used in apps that don't have + // appmodules.so + } + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultTurboModuleManagerDelegate.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultTurboModuleManagerDelegate.kt index ac1fd1a4c7d90c..a8644376293d43 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultTurboModuleManagerDelegate.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultTurboModuleManagerDelegate.kt @@ -12,6 +12,8 @@ import com.facebook.proguard.annotations.DoNotStrip import com.facebook.react.ReactPackage import com.facebook.react.ReactPackageTurboModuleManagerDelegate import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.runtime.cxxreactpackage.CxxReactPackage /** * A utility class that allows you to simplify the setup of a @@ -20,14 +22,54 @@ import com.facebook.react.bridge.ReactApplicationContext * This class works together with the [DefaultNewArchitectureEntryPoint] and it's C++ implementation * is hosted inside the React Native framework */ +@OptIn(UnstableReactNativeAPI::class) class DefaultTurboModuleManagerDelegate -private constructor(context: ReactApplicationContext, packages: List) : - ReactPackageTurboModuleManagerDelegate(context, packages) { +private constructor( + context: ReactApplicationContext, + packages: List, + private val eagerlyInitializedModules: List, + cxxReactPackages: List, +) : ReactPackageTurboModuleManagerDelegate(context, packages, initHybrid(cxxReactPackages)) { - @DoNotStrip external override fun initHybrid(): HybridData? + override fun initHybrid(): HybridData? { + throw UnsupportedOperationException( + "DefaultTurboModuleManagerDelegate.initHybrid() must never be called!") + } + + override fun getEagerInitModuleNames(): List { + if (unstable_isLazyTurboModuleDelegate()) { + return eagerlyInitializedModules + } + + // Use ReactModuleInfo to get the eager init module names + return super.getEagerInitModuleNames() + } class Builder : ReactPackageTurboModuleManagerDelegate.Builder() { + private var eagerInitModuleNames: List = emptyList() + private var cxxReactPackages: MutableList = mutableListOf() + + fun setEagerInitModuleNames(eagerInitModuleNames: List): Builder { + this.eagerInitModuleNames = eagerInitModuleNames + return this + } + + fun addCxxReactPackage(cxxReactPackage: CxxReactPackage): Builder { + this.cxxReactPackages.add(cxxReactPackage) + return this + } + override fun build(context: ReactApplicationContext, packages: List) = - DefaultTurboModuleManagerDelegate(context, packages) + DefaultTurboModuleManagerDelegate(context, packages, eagerInitModuleNames, cxxReactPackages) + } + + companion object { + init { + DefaultSoLoader.maybeLoadSoLibrary() + } + + @DoNotStrip + @JvmStatic + external fun initHybrid(cxxReactPackages: List): HybridData? } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java index 2b4e4eabb64a98..b9ab16eb9f95d1 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java @@ -363,15 +363,16 @@ public void onOptionSelected() { } }); - if (mDevSettings.isDeviceDebugEnabled()) { - // On-device JS debugging (CDP). Render action to open debugger frontend. + if (mDevSettings.isRemoteJSDebugEnabled()) { + // [Deprecated in React Native 0.73] Remote JS debugging. Handle reload + // via external JS executor. This capability will be removed in a future + // release. + mDevSettings.setRemoteJSDebugEnabled(false); + handleReloadJS(); + } - // Reset the old debugger setting so no one gets stuck. - // TODO: Remove in a few weeks. - if (mDevSettings.isRemoteJSDebugEnabled()) { - mDevSettings.setRemoteJSDebugEnabled(false); - handleReloadJS(); - } + if (mDevSettings.isDeviceDebugEnabled() && !mDevSettings.isRemoteJSDebugEnabled()) { + // On-device JS debugging (CDP). Render action to open debugger frontend. options.put( mApplicationContext.getString(R.string.catalyst_debug_open), () -> @@ -413,9 +414,7 @@ public void onClick(DialogInterface dialog, int which) { }); options.put( - mDevSettings.isElementInspectorEnabled() - ? mApplicationContext.getString(R.string.catalyst_inspector_stop) - : mApplicationContext.getString(R.string.catalyst_inspector), + mApplicationContext.getString(R.string.catalyst_inspector_toggle), new DevOptionHandler() { @Override public void onOptionSelected() { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java index 7a083c9870b322..3261a598b041f3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java @@ -362,7 +362,7 @@ private void executeOrEnqueue(MountItem item) { } SurfaceMountingManager surfaceMountingManager = mMountingManager.getSurfaceManager(item.getSurfaceId()); - surfaceMountingManager.executeOnViewAttach(item); + surfaceMountingManager.scheduleMountItemOnViewAttach(item); } else { item.execute(mMountingManager); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index e65a01cd25e158..3aa8c930349271 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -143,9 +143,12 @@ public void stopSurface(final int surfaceId) { surfaceMountingManager.stopSurface(); - if (surfaceMountingManager == mMostRecentSurfaceMountingManager) { + if (mMostRecentSurfaceMountingManager == surfaceMountingManager) { mMostRecentSurfaceMountingManager = null; } + if (mLastQueriedSurfaceMountingManager == surfaceMountingManager) { + mLastQueriedSurfaceMountingManager = null; + } } else { ReactSoftExceptionLogger.logSoftException( TAG, diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java index 87b15e454f3127..90267da55b369a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java @@ -52,6 +52,7 @@ import com.facebook.react.uimanager.events.EventCategoryDef; import com.facebook.react.views.view.ReactMapBufferViewManager; import com.facebook.react.views.view.ReactViewManagerWrapper; +import java.util.ArrayDeque; import java.util.HashSet; import java.util.LinkedList; import java.util.Map; @@ -59,7 +60,6 @@ import java.util.Set; import java.util.Stack; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; public class SurfaceMountingManager { public static final String TAG = SurfaceMountingManager.class.getSimpleName(); @@ -74,7 +74,7 @@ public class SurfaceMountingManager { // These are all non-null, until StopSurface is called private ConcurrentHashMap mTagToViewState = new ConcurrentHashMap<>(); // any thread - private ConcurrentLinkedQueue mOnViewAttachItems = new ConcurrentLinkedQueue<>(); + private Queue mOnViewAttachMountItems = new ArrayDeque<>(); private JSResponderHandler mJSResponderHandler; private ViewManagerRegistry mViewManagerRegistry; private RootViewManager mRootViewManager; @@ -181,9 +181,10 @@ public boolean getViewExists(int tag) { return mTagToViewState.containsKey(tag); } - @AnyThread - public void executeOnViewAttach(MountItem item) { - mOnViewAttachItems.add(item); + @UiThread + @ThreadConfined(UI) + public void scheduleMountItemOnViewAttach(MountItem item) { + mOnViewAttachMountItems.add(item); } @AnyThread @@ -233,7 +234,7 @@ private void addRootView(@NonNull final View rootView) { } mRootViewAttached = true; - executeViewAttachMountItems(); + executeMountItemsOnViewAttach(); }; if (UiThreadUtil.isOnUiThread()) { @@ -245,8 +246,8 @@ private void addRootView(@NonNull final View rootView) { @UiThread @ThreadConfined(UI) - private void executeViewAttachMountItems() { - mMountItemExecutor.executeItems(mOnViewAttachItems); + private void executeMountItemsOnViewAttach() { + mMountItemExecutor.executeItems(mOnViewAttachMountItems); } /** @@ -319,7 +320,7 @@ public void stopSurface() { mRootViewManager = null; mMountItemExecutor = null; mThemedReactContext = null; - mOnViewAttachItems.clear(); + mOnViewAttachMountItems.clear(); if (ReactFeatureFlags.enableViewRecycling) { mViewManagerRegistry.onSurfaceStopped(mSurfaceId); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManagerDelegate.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManagerDelegate.java index 2740fa7208ae7d..7cb82679a3aefa 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManagerDelegate.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManagerDelegate.java @@ -31,6 +31,11 @@ protected TurboModuleManagerDelegate() { mHybridData = initHybrid(); } + protected TurboModuleManagerDelegate(HybridData hybridData) { + maybeLoadOtherSoLibraries(); + mHybridData = hybridData; + } + /** * Create and return a TurboModule Java object with name `moduleName`. If `moduleName` isn't a * TurboModule, return null. @@ -77,5 +82,7 @@ public boolean unstable_enableSyncVoidMethods() { return false; } + // TODO(T171231381): Consider removing this method: could we just use the static initializer + // of derived classes instead? protected synchronized void maybeLoadOtherSoLibraries() {} } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java index ad4b76d4b549dc..6e1994a3804d00 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java @@ -21,6 +21,7 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactNoCrashBridgeNotAllowedSoftException; import com.facebook.react.bridge.ReactSoftExceptionLogger; +import com.facebook.react.bridge.UIManager; import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.config.ReactFeatureFlags; import com.facebook.react.devsupport.interfaces.DevSupportManager; @@ -84,6 +85,11 @@ public void setSourceURL(String sourceURL) { + moduleType.name()); } + @Override + public @Nullable UIManager getFabricUIManager() { + return mReactHost.getUIManager(); + } + @Override public CatalystInstance getCatalystInstance() { ReactSoftExceptionLogger.logSoftExceptionVerbose( diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/CoreReactPackage.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/CoreReactPackage.java index 2550520a48641e..cb8b9c13af09ae 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/CoreReactPackage.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/CoreReactPackage.java @@ -7,6 +7,7 @@ package com.facebook.react.runtime; +import androidx.annotation.Nullable; import com.facebook.infer.annotation.Nullsafe; import com.facebook.react.TurboReactPackage; import com.facebook.react.bridge.NativeModule; @@ -51,7 +52,7 @@ public CoreReactPackage( } @Override - public NativeModule getModule(String name, ReactApplicationContext reactContext) { + public @Nullable NativeModule getModule(String name, ReactApplicationContext reactContext) { switch (name) { case AndroidInfoModule.NAME: return new AndroidInfoModule(reactContext); @@ -68,8 +69,7 @@ public NativeModule getModule(String name, ReactApplicationContext reactContext) case ExceptionsManagerModule.NAME: return new ExceptionsManagerModule(mDevSupportManager); default: - throw new IllegalArgumentException( - "In BridgelessReactPackage, could not find Native module for " + name); + return null; } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/JSCInstance.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/JSCInstance.java index 8fb32073cfafed..0524c58eac2312 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/JSCInstance.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/JSCInstance.java @@ -13,7 +13,7 @@ import com.facebook.soloader.SoLoader; @Nullsafe(Nullsafe.Mode.LOCAL) -public class JSCInstance extends JSEngineInstance { +public class JSCInstance extends JSRuntimeFactory { static { SoLoader.loadLibrary("jscinstance"); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/JSEngineInstance.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/JSRuntimeFactory.java similarity index 85% rename from packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/JSEngineInstance.java rename to packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/JSRuntimeFactory.java index 708e71676641d3..83d3e9f841a801 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/JSEngineInstance.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/JSRuntimeFactory.java @@ -13,14 +13,14 @@ import com.facebook.soloader.SoLoader; @Nullsafe(Nullsafe.Mode.LOCAL) -public abstract class JSEngineInstance { +public abstract class JSRuntimeFactory { static { SoLoader.loadLibrary("rninstance"); } @DoNotStrip private final HybridData mHybridData; - protected JSEngineInstance(HybridData hybridData) { + protected JSRuntimeFactory(HybridData hybridData) { mHybridData = hybridData; } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostDelegate.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostDelegate.kt index a26880fc71df4b..6b9f71d1f6f02f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostDelegate.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostDelegate.kt @@ -38,7 +38,7 @@ interface ReactHostDelegate { val reactPackages: List /** Object that holds a native reference to the javascript engine */ - val jsEngineInstance: JSEngineInstance + val jsRuntimeFactory: JSRuntimeFactory /** * Bundle loader to use when setting up JS environment.

Example: @@ -68,7 +68,7 @@ interface ReactHostDelegate { class ReactHostDelegateBase( override val jsMainModulePath: String, override val jsBundleLoader: JSBundleLoader, - override val jsEngineInstance: JSEngineInstance, + override val jsRuntimeFactory: JSRuntimeFactory, override val turboModuleManagerDelegateBuilder: ReactPackageTurboModuleManagerDelegate.Builder, override val reactPackages: List = emptyList(), diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java index 8d1b0a52137571..e5e36fe7709deb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java @@ -167,7 +167,7 @@ public void onHostDestroy() { } }); - JSEngineInstance jsEngineInstance = mDelegate.getJsEngineInstance(); + JSRuntimeFactory jsRuntimeFactory = mDelegate.getJsRuntimeFactory(); BindingsInstaller bindingsInstaller = mDelegate.getBindingsInstaller(); // Notify JS if profiling is enabled boolean isProfiling = @@ -177,7 +177,7 @@ public void onHostDestroy() { boolean useModernRuntimeScheduler = ReactFeatureFlags.useModernRuntimeScheduler; mHybridData = initHybrid( - jsEngineInstance, + jsRuntimeFactory, jsMessageQueueThread, nativeModulesMessageQueueThread, mJavaTimerManager, @@ -432,7 +432,7 @@ public Collection getNativeModules() { @DoNotStrip private native HybridData initHybrid( - JSEngineInstance jsEngineInstance, + JSRuntimeFactory jsRuntimeFactory, MessageQueueThread jsMessageQueueThread, MessageQueueThread nativeModulesMessageQueueThread, JavaTimerManager timerManager, diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/cxxreactpackage/CxxReactPackage.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/cxxreactpackage/CxxReactPackage.kt new file mode 100644 index 00000000000000..12cfb9ac017292 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/cxxreactpackage/CxxReactPackage.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// TODO(170197717): Consider moving this to runtime.cxx, or just runtime +package com.facebook.react.runtime.cxxreactpackage + +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.soloader.SoLoader + +/** CxxReactPackage is used to register C++ Turbo Modules with React Native. */ +@UnstableReactNativeAPI() +abstract class CxxReactPackage { + + @DoNotStrip @Suppress("NoHungarianNotation") private var mHybridData: HybridData? + + protected constructor(hybridData: HybridData?) { + mHybridData = hybridData + } + + companion object { + init { + SoLoader.loadLibrary("react_cxxreactpackage") + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/hermes/HermesInstance.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/hermes/HermesInstance.kt index 7c96e99b6a5c4e..e20bc7ca0b474e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/hermes/HermesInstance.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/hermes/HermesInstance.kt @@ -10,11 +10,11 @@ package com.facebook.react.runtime.hermes import com.facebook.jni.HybridData import com.facebook.jni.annotations.DoNotStrip import com.facebook.react.fabric.ReactNativeConfig -import com.facebook.react.runtime.JSEngineInstance +import com.facebook.react.runtime.JSRuntimeFactory import com.facebook.soloader.SoLoader class HermesInstance constructor(reactNativeConfig: ReactNativeConfig?) : - JSEngineInstance(initHybrid(reactNativeConfig as Any?)) { + JSRuntimeFactory(initHybrid(reactNativeConfig as Any?)) { constructor() : this(null) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java index b10d2d9b3c0681..eded794637a424 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java @@ -15,6 +15,7 @@ import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.UIManager; /** * Wraps {@link ReactContext} with the base {@link Context} passed into the constructor. It provides @@ -116,4 +117,12 @@ public JSIModule getJSIModule(JSIModuleType moduleType) { } return super.getJSIModule(moduleType); } + + @Override + public UIManager getFabricUIManager() { + if (isBridgeless()) { + return mReactApplicationContext.getFabricUIManager(); + } + return super.getFabricUIManager(); + } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.java index c4a3902d1e3d6a..daa1295fc7b59f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.java @@ -17,7 +17,6 @@ import androidx.annotation.Nullable; import androidx.core.view.ViewCompat; import com.facebook.react.bridge.CatalystInstance; -import com.facebook.react.bridge.JSIModuleType; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactNoCrashSoftException; import com.facebook.react.bridge.ReactSoftExceptionLogger; @@ -53,7 +52,11 @@ private static UIManager getUIManager( @UIManagerType int uiManagerType, boolean returnNullIfCatalystIsInactive) { if (context.isBridgeless()) { - @Nullable UIManager uiManager = (UIManager) context.getJSIModule(JSIModuleType.UIManager); + if (!context.hasActiveReactInstance()) { + throw new IllegalStateException( + "Unable to retrieve a UIManager if CatalystInstance is not active."); + } + @Nullable UIManager uiManager = context.getFabricUIManager(); if (uiManager == null) { ReactSoftExceptionLogger.logSoftException( TAG, @@ -85,7 +88,7 @@ private static UIManager getUIManager( CatalystInstance catalystInstance = context.getCatalystInstance(); try { return uiManagerType == FABRIC - ? (UIManager) catalystInstance.getJSIModule(JSIModuleType.UIManager) + ? context.getFabricUIManager() : catalystInstance.getNativeModule(UIManagerModule.class); } catch (IllegalArgumentException ex) { // TODO T67518514 Clean this up once we migrate everything over to bridgeless mode diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/FabricEventDispatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/FabricEventDispatcher.java index 953649288c239a..a1515559cd1642 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/FabricEventDispatcher.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/FabricEventDispatcher.java @@ -11,6 +11,7 @@ import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.UiThreadUtil; +import com.facebook.react.config.ReactFeatureFlags; import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.uimanager.common.UIManagerType; import com.facebook.systrace.Systrace; @@ -84,7 +85,9 @@ public void removeBatchEventDispatchedListener(BatchEventDispatchedListener list @Override public void onHostResume() { - maybePostFrameCallbackFromNonUI(); + if (!ReactFeatureFlags.enableOnDemandReactChoreographer) { + maybePostFrameCallbackFromNonUI(); + } } @Override @@ -94,17 +97,21 @@ public void onHostPause() { @Override public void onHostDestroy() { - stopFrameCallback(); + if (!ReactFeatureFlags.enableOnDemandReactChoreographer) { + stopFrameCallback(); + } } public void onCatalystInstanceDestroyed() { - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - stopFrameCallback(); - } - }); + if (!ReactFeatureFlags.enableOnDemandReactChoreographer) { + UiThreadUtil.runOnUiThread( + new Runnable() { + @Override + public void run() { + stopFrameCallback(); + } + }); + } } private void stopFrameCallback() { @@ -133,7 +140,7 @@ private class ScheduleDispatchFrameCallback implements Choreographer.FrameCallba public void doFrame(long frameTimeNanos) { UiThreadUtil.assertOnUiThread(); - if (mShouldStop) { + if (ReactFeatureFlags.enableOnDemandReactChoreographer || mShouldStop) { mIsPosted = false; } else { post(); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/traceupdateoverlay/TraceUpdateOverlay.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/debuggingoverlay/DebuggingOverlay.java similarity index 92% rename from packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/traceupdateoverlay/TraceUpdateOverlay.java rename to packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/debuggingoverlay/DebuggingOverlay.java index 6799848284828f..0ebaf4b8743866 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/traceupdateoverlay/TraceUpdateOverlay.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/debuggingoverlay/DebuggingOverlay.java @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.react.views.traceupdateoverlay; +package com.facebook.react.views.debuggingoverlay; import android.content.Context; import android.graphics.Canvas; @@ -17,7 +17,7 @@ import java.util.ArrayList; import java.util.List; -public class TraceUpdateOverlay extends View { +public class DebuggingOverlay extends View { private final Paint mOverlayPaint = new Paint(); private List mOverlays = new ArrayList(); @@ -43,7 +43,7 @@ public RectF getPixelRect() { } } - public TraceUpdateOverlay(Context context) { + public DebuggingOverlay(Context context) { super(context); mOverlayPaint.setStyle(Paint.Style.STROKE); mOverlayPaint.setStrokeWidth(6); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/traceupdateoverlay/TraceUpdateOverlayManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/debuggingoverlay/DebuggingOverlayManager.java similarity index 76% rename from packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/traceupdateoverlay/TraceUpdateOverlayManager.java rename to packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/debuggingoverlay/DebuggingOverlayManager.java index 434be098b1a2fa..cacdd5c4dbfeda 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/traceupdateoverlay/TraceUpdateOverlayManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/debuggingoverlay/DebuggingOverlayManager.java @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.react.views.traceupdateoverlay; +package com.facebook.react.views.debuggingoverlay; import android.graphics.RectF; import androidx.annotation.Nullable; @@ -16,22 +16,22 @@ import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.SimpleViewManager; import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.views.traceupdateoverlay.TraceUpdateOverlay.Overlay; +import com.facebook.react.views.debuggingoverlay.DebuggingOverlay.Overlay; import java.util.ArrayList; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -@ReactModule(name = TraceUpdateOverlayManager.REACT_CLASS) -public class TraceUpdateOverlayManager extends SimpleViewManager { - public static final String REACT_CLASS = "TraceUpdateOverlay"; +@ReactModule(name = DebuggingOverlayManager.REACT_CLASS) +public class DebuggingOverlayManager extends SimpleViewManager { + public static final String REACT_CLASS = "DebuggingOverlay"; - public TraceUpdateOverlayManager() {} + public DebuggingOverlayManager() {} @Override public void receiveCommand( - TraceUpdateOverlay view, String commandId, @Nullable ReadableArray args) { + DebuggingOverlay view, String commandId, @Nullable ReadableArray args) { switch (commandId) { case "draw": if (args == null) { @@ -67,13 +67,13 @@ public void receiveCommand( ReactSoftExceptionLogger.logSoftException( REACT_CLASS, new ReactNoCrashSoftException( - "Received unexpected command in TraceUpdateOverlayManager")); + "Received unexpected command in DebuggingOverlayManager")); } } @Override - public TraceUpdateOverlay createViewInstance(ThemedReactContext context) { - return new TraceUpdateOverlay(context); + public DebuggingOverlay createViewInstance(ThemedReactContext context) { + return new DebuggingOverlay(context); } @Override diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 8496a7d059e4c8..0816eeb102e4f4 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -168,14 +168,11 @@ public class ReactTextInputManager extends BaseViewManager= Build.VERSION_CODES.Q) { - Drawable cursorDrawable = view.getTextCursorDrawable(); - if (cursorDrawable != null) { - cursorDrawable.setColorFilter(new BlendModeColorFilter(color, BlendMode.SRC_IN)); - view.setTextCursorDrawable(cursorDrawable); + Drawable drawableCenter = view.getTextSelectHandle().mutate(); + Drawable drawableLeft = view.getTextSelectHandleLeft().mutate(); + Drawable drawableRight = view.getTextSelectHandleRight().mutate(); + if (color != null) { + BlendModeColorFilter filter = new BlendModeColorFilter(color, BlendMode.SRC_IN); + drawableCenter.setColorFilter(filter); + drawableLeft.setColorFilter(filter); + drawableRight.setColorFilter(filter); + } else { + drawableCenter.clearColorFilter(); + drawableLeft.clearColorFilter(); + drawableRight.clearColorFilter(); } + view.setTextSelectHandle(drawableCenter); + view.setTextSelectHandleLeft(drawableLeft); + view.setTextSelectHandleRight(drawableRight); return; } + // Based on https://github.com/facebook/react-native/pull/31007 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) { - // Pre-Android 10, there was no supported API to change the cursor color programmatically. - // In Android 9.0, they changed the underlying implementation, - // but also "dark greylisted" the new field, rendering it unusable. return; } - // The evil code that follows uses reflection to achieve this on Android 8.1 and below. - // Based on https://tinyurl.com/3vff8lyu https://tinyurl.com/vehggzs9 - for (int i = 0; i < DRAWABLE_RESOURCES.length; i++) { + // The following code uses reflection to change handles color on Android 8.1 and below. + for (int i = 0; i < DRAWABLE_HANDLE_RESOURCES.length; i++) { try { - Field drawableResourceField = TextView.class.getDeclaredField(DRAWABLE_RESOURCES[i]); + Field drawableResourceField = + view.getClass().getDeclaredField(DRAWABLE_HANDLE_RESOURCES[i]); drawableResourceField.setAccessible(true); int resourceId = drawableResourceField.getInt(view); - // The view has no cursor drawable. + // The view has no handle drawable. if (resourceId == 0) { return; } - Drawable drawable = ContextCompat.getDrawable(view.getContext(), resourceId); - - Drawable drawableCopy = drawable.mutate(); - drawableCopy.setColorFilter(color, PorterDuff.Mode.SRC_IN); + Drawable drawable = ContextCompat.getDrawable(view.getContext(), resourceId).mutate(); + if (color != null) { + drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); + } else { + drawable.clearColorFilter(); + } Field editorField = TextView.class.getDeclaredField("mEditor"); editorField.setAccessible(true); Object editor = editorField.get(view); - Field cursorDrawableField = editor.getClass().getDeclaredField(DRAWABLE_FIELDS[i]); + Field cursorDrawableField = editor.getClass().getDeclaredField(DRAWABLE_HANDLE_FIELDS[i]); cursorDrawableField.setAccessible(true); - if (DRAWABLE_RESOURCES[i] == "mCursorDrawableRes") { - Drawable[] drawables = {drawableCopy, drawableCopy}; - cursorDrawableField.set(editor, drawables); - } else { - cursorDrawableField.set(editor, drawableCopy); - } + cursorDrawableField.set(editor, drawable); } catch (NoSuchFieldException ex) { - // Ignore errors to avoid crashing if these private fields don't exist on modified - // or future android versions. } catch (IllegalAccessException ex) { } } } + @ReactProp(name = "cursorColor", customType = "Color") + public void setCursorColor(ReactEditText view, @Nullable Integer color) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Drawable cursorDrawable = view.getTextCursorDrawable(); + if (cursorDrawable != null) { + if (color != null) { + cursorDrawable.setColorFilter(new BlendModeColorFilter(color, BlendMode.SRC_IN)); + } else { + cursorDrawable.clearColorFilter(); + } + view.setTextCursorDrawable(cursorDrawable); + } + return; + } + + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) { + // Pre-Android 10, there was no supported API to change the cursor color programmatically. + // In Android 9.0, they changed the underlying implementation, + // but also "dark greylisted" the new field, rendering it unusable. + return; + } + + // The evil code that follows uses reflection to achieve this on Android 8.1 and below. + // Based on https://tinyurl.com/3vff8lyu https://tinyurl.com/vehggzs9 + try { + Field drawableCursorField = view.getClass().getDeclaredField("mCursorDrawableRes"); + drawableCursorField.setAccessible(true); + int resourceId = drawableCursorField.getInt(view); + + // The view has no cursor drawable. + if (resourceId == 0) { + return; + } + + Drawable drawable = ContextCompat.getDrawable(view.getContext(), resourceId).mutate(); + if (color != null) { + drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); + } else { + drawable.clearColorFilter(); + } + + Field editorField = TextView.class.getDeclaredField("mEditor"); + editorField.setAccessible(true); + Object editor = editorField.get(view); + + Field cursorDrawableField = editor.getClass().getDeclaredField("mCursorDrawable"); + cursorDrawableField.setAccessible(true); + Drawable[] drawables = {drawable, drawable}; + cursorDrawableField.set(editor, drawables); + } catch (NoSuchFieldException ex) { + // Ignore errors to avoid crashing if these private fields don't exist on modified + // or future android versions. + } catch (IllegalAccessException ex) { + } + } + private static boolean shouldHideCursorForEmailTextInput() { String manufacturer = Build.MANUFACTURER.toLowerCase(Locale.ROOT); return (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q && manufacturer.contains("xiaomi")); diff --git a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt index e765f9b67f3708..feb7a3b33cafdd 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt @@ -121,6 +121,7 @@ add_react_android_subdir(src/main/jni/react/fabric) add_react_android_subdir(src/main/jni/react/newarchdefaults) add_react_android_subdir(src/main/jni/react/hermes/reactexecutor) add_react_android_subdir(src/main/jni/react/hermes/instrumentation/) +add_react_android_subdir(src/main/jni/react/runtime/cxxreactpackage) add_react_android_subdir(src/main/jni/react/runtime/jni) add_react_android_subdir(src/main/jni/react/runtime/hermes/jni) add_react_android_subdir(src/main/jni/react/runtime/jsc/jni) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp index 0f89b1ee8fe29b..1024afce2b7c9a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp @@ -424,6 +424,8 @@ void Binding::installFabricUIManager( getFeatureFlagValue("enableClonelessStateProgression"); CoreFeatures::excludeYogaFromRawProps = getFeatureFlagValue("excludeYogaFromRawProps"); + CoreFeatures::positionRelativeDefault = + getFeatureFlagValue("positionRelativeDefault"); // RemoveDelete mega-op ShadowViewMutation::PlatformSupportsRemoveDeleteTreeInstruction = diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.h index d447a501ef0394..b310f3bd2962be 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.h @@ -34,7 +34,11 @@ class ReactNativeConfig; class Scheduler; class SurfaceHandlerBinding; -class Binding : public jni::HybridClass, +struct JBinding : public jni::JavaClass { + constexpr static auto kJavaDescriptor = "Lcom/facebook/react/fabric/Binding;"; +}; + +class Binding : public jni::HybridClass, public SchedulerDelegate, public LayoutAnimationStatusDelegate { public: diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.cpp index 5cc5aae68d5bff..99ddee8b3b1dd1 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.cpp @@ -66,7 +66,7 @@ CoreComponentsRegistry::sharedProviderRegistry() { providerRegistry->add(concreteComponentDescriptorProvider< AndroidDrawerLayoutComponentDescriptor>()); providerRegistry->add(concreteComponentDescriptorProvider< - TraceUpdateOverlayComponentDescriptor>()); + DebuggingOverlayComponentDescriptor>()); return providerRegistry; }(); diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JFabricUIManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JFabricUIManager.cpp index a2ccdbf5d57078..48326b97c260b3 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JFabricUIManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JFabricUIManager.cpp @@ -13,8 +13,9 @@ namespace facebook::react { Binding* JFabricUIManager::getBinding() { static const auto bindingField = - javaClassStatic()->getField("mBinding"); + javaClassStatic()->getField("mBinding"); - return getFieldValue(bindingField)->cthis(); + return jni::static_ref_cast(getFieldValue(bindingField)) + ->cthis(); } } // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/CMakeLists.txt index 166c5ed45344ec..b928ca15839865 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/CMakeLists.txt @@ -19,4 +19,5 @@ target_link_libraries(react_newarchdefaults fabricjni react_nativemodule_core react_codegen_rncore + react_cxxreactpackage jsi) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.cpp index c4a14f39c5349c..e202896abc7bad 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.cpp @@ -7,10 +7,26 @@ #include "DefaultTurboModuleManagerDelegate.h" +#include + #include namespace facebook::react { +DefaultTurboModuleManagerDelegate::DefaultTurboModuleManagerDelegate( + jni::alias_ref::javaobject> + cxxReactPackages) + : cxxReactPackages_() { + cxxReactPackages_.reserve(cxxReactPackages->size()); + std::transform( + cxxReactPackages->begin(), + cxxReactPackages->end(), + std::back_inserter(cxxReactPackages_), + [](jni::alias_ref elem) { + return jni::make_global(elem); + }); +}; + std::function( const std::string&, const std::shared_ptr&)> @@ -22,8 +38,11 @@ std::function( DefaultTurboModuleManagerDelegate::javaModuleProvider{nullptr}; jni::local_ref -DefaultTurboModuleManagerDelegate::initHybrid(jni::alias_ref) { - return makeCxxInstance(); +DefaultTurboModuleManagerDelegate::initHybrid( + jni::alias_ref jClass, + jni::alias_ref::javaobject> + cxxReactPackages) { + return makeCxxInstance(cxxReactPackages); } void DefaultTurboModuleManagerDelegate::registerNatives() { @@ -36,6 +55,16 @@ void DefaultTurboModuleManagerDelegate::registerNatives() { std::shared_ptr DefaultTurboModuleManagerDelegate::getTurboModule( const std::string& name, const std::shared_ptr& jsInvoker) { + for (const auto& cxxReactPackage : cxxReactPackages_) { + auto cppPart = cxxReactPackage->cthis(); + if (cppPart) { + auto module = cppPart->getModule(name, jsInvoker); + if (module) { + return module; + } + } + } + auto moduleProvider = DefaultTurboModuleManagerDelegate::cxxModuleProvider; if (moduleProvider) { return moduleProvider(name, jsInvoker); diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.h b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.h index fdcf8d00ae9b22..099c245f574df9 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.h @@ -7,7 +7,9 @@ #include #include +#include +#include #include #include #include @@ -22,7 +24,9 @@ class DefaultTurboModuleManagerDelegate : public jni::HybridClass< static constexpr auto kJavaDescriptor = "Lcom/facebook/react/defaults/DefaultTurboModuleManagerDelegate;"; - static jni::local_ref initHybrid(jni::alias_ref); + static jni::local_ref initHybrid( + jni::alias_ref, + jni::alias_ref::javaobject>); static void registerNatives(); @@ -46,6 +50,12 @@ class DefaultTurboModuleManagerDelegate : public jni::HybridClass< private: friend HybridBase; using HybridBase::HybridBase; + + std::vector> cxxReactPackages_; + + DefaultTurboModuleManagerDelegate( + jni::alias_ref::javaobject> + cxxReactPackage); }; } // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/cxxreactpackage/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/cxxreactpackage/CMakeLists.txt new file mode 100644 index 00000000000000..3cea95847728f8 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/cxxreactpackage/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +add_compile_options( + -fexceptions + -frtti + -Wno-unused-lambda-capture + -std=c++20) + + +######################### +### cxxreactpackage ### +######################### + +add_library(react_cxxreactpackage SHARED ReactCommon/OnLoad.cpp) + +target_include_directories(react_cxxreactpackage + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(react_cxxreactpackage + fb + fbjni) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/cxxreactpackage/ReactCommon/CxxReactPackage.h b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/cxxreactpackage/ReactCommon/CxxReactPackage.h new file mode 100644 index 00000000000000..cdf1a86a7f4252 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/cxxreactpackage/ReactCommon/CxxReactPackage.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook::react { + +class TurboModule; +class CallInvoker; + +class CxxReactPackage : public jni::HybridClass { + public: + static auto constexpr kJavaDescriptor = + "Lcom/facebook/react/runtime/cxxreactpackage/CxxReactPackage;"; + + virtual std::shared_ptr getModule( + const std::string& name, + const std::shared_ptr& jsInvoker) = 0; + + private: + friend HybridBase; +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/cxxreactpackage/ReactCommon/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/cxxreactpackage/ReactCommon/OnLoad.cpp new file mode 100644 index 00000000000000..e7f1f355b50be0 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/cxxreactpackage/ReactCommon/OnLoad.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include "CxxReactPackage.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { + return facebook::jni::initialize(vm, [] {}); +} diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/JHermesInstance.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/JHermesInstance.cpp index 3d8a9f74652443..deabc529969432 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/JHermesInstance.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/JHermesInstance.cpp @@ -28,7 +28,7 @@ void JHermesInstance::registerNatives() { }); } -std::unique_ptr JHermesInstance::createJSRuntime( +std::unique_ptr JHermesInstance::createJSRuntime( std::shared_ptr msgQueueThread) noexcept { return HermesInstance::createJSRuntime( reactNativeConfig_, nullptr, msgQueueThread); diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/JHermesInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/JHermesInstance.h index 9d500aaa3c3c30..5ee3450442db92 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/JHermesInstance.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/hermes/jni/JHermesInstance.h @@ -14,14 +14,14 @@ #include #include #include -#include +#include #include -#include "../../jni/JJSEngineInstance.h" +#include "../../jni/JJSRuntimeFactory.h" namespace facebook::react { class JHermesInstance - : public jni::HybridClass { + : public jni::HybridClass { public: static constexpr auto kJavaDescriptor = "Lcom/facebook/react/runtime/hermes/HermesInstance;"; @@ -35,7 +35,7 @@ class JHermesInstance JHermesInstance(std::shared_ptr reactNativeConfig) : reactNativeConfig_(reactNativeConfig){}; - std::unique_ptr createJSRuntime( + std::unique_ptr createJSRuntime( std::shared_ptr msgQueueThread) noexcept; ~JHermesInstance() {} diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JJSEngineInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JJSRuntimeFactory.h similarity index 64% rename from packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JJSEngineInstance.h rename to packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JJSRuntimeFactory.h index 06619c451c6805..03c312cd378dbc 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JJSEngineInstance.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JJSRuntimeFactory.h @@ -9,15 +9,15 @@ #include #include -#include +#include namespace facebook::react { -class JJSEngineInstance : public jni::HybridClass, - public JSEngineInstance { +class JJSRuntimeFactory : public jni::HybridClass, + public JSRuntimeFactory { public: static auto constexpr kJavaDescriptor = - "Lcom/facebook/react/runtime/JSEngineInstance;"; + "Lcom/facebook/react/runtime/JSRuntimeFactory;"; private: friend HybridBase; diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp index 325c3c32d0646d..09a46dc4e58c90 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp @@ -29,7 +29,7 @@ namespace facebook::react { JReactInstance::JReactInstance( - jni::alias_ref jsEngineInstance, + jni::alias_ref jsRuntimeFactory, jni::alias_ref jsMessageQueueThread, jni::alias_ref nativeMessageQueueThread, jni::alias_ref javaTimerManager, @@ -62,7 +62,7 @@ JReactInstance::JReactInstance( jBindingsInstaller_ = jni::make_global(jBindingsInstaller); instance_ = std::make_unique( - jsEngineInstance->cthis()->createJSRuntime(sharedJSMessageQueueThread), + jsRuntimeFactory->cthis()->createJSRuntime(sharedJSMessageQueueThread), sharedJSMessageQueueThread, timerManager, std::move(jsErrorHandlingFunc), @@ -110,7 +110,7 @@ JReactInstance::JReactInstance( jni::local_ref JReactInstance::initHybrid( jni::alias_ref /* unused */, - jni::alias_ref jsEngineInstance, + jni::alias_ref jsRuntimeFactory, jni::alias_ref jsMessageQueueThread, jni::alias_ref nativeMessageQueueThread, jni::alias_ref javaTimerManager, @@ -120,7 +120,7 @@ jni::local_ref JReactInstance::initHybrid( bool isProfiling, bool useModernRuntimeScheduler) { return makeCxxInstance( - jsEngineInstance, + jsRuntimeFactory, jsMessageQueueThread, nativeMessageQueueThread, javaTimerManager, diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h index 0fd9a28a438a28..41ea4891bd50bf 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h @@ -18,12 +18,12 @@ #include #include #include -#include +#include #include #include #include "JBindingsInstaller.h" -#include "JJSEngineInstance.h" +#include "JJSRuntimeFactory.h" #include "JJSTimerExecutor.h" #include "JJavaTimerManager.h" #include "JReactExceptionManager.h" @@ -37,7 +37,7 @@ class JReactInstance : public jni::HybridClass { static jni::local_ref initHybrid( jni::alias_ref, - jni::alias_ref jsEngineInstance, + jni::alias_ref jsRuntimeFactory, jni::alias_ref jsMessageQueueThread, jni::alias_ref nativeMessageQueueThread, @@ -83,7 +83,7 @@ class JReactInstance : public jni::HybridClass { friend HybridBase; explicit JReactInstance( - jni::alias_ref jsEngineInstance, + jni::alias_ref jsRuntimeFactory, jni::alias_ref jsMessageQueueThread, jni::alias_ref nativeMessageQueueThread, diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jsc/jni/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jsc/jni/OnLoad.cpp index 02e384cac712dd..e49a55d50243c8 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jsc/jni/OnLoad.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jsc/jni/OnLoad.cpp @@ -10,12 +10,12 @@ #include #include #include -#include -#include +#include +#include namespace facebook::react { -class JSCInstance : public jni::HybridClass { +class JSCInstance : public jni::HybridClass { public: static constexpr auto kJavaDescriptor = "Lcom/facebook/react/runtime/JSCInstance;"; @@ -30,9 +30,9 @@ class JSCInstance : public jni::HybridClass { }); } - std::unique_ptr createJSRuntime( + std::unique_ptr createJSRuntime( std::shared_ptr msgQueueThread) noexcept { - return jsc::makeJSCRuntime(); + return std::make_unique(jsc::makeJSCRuntime()); } private: diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values/strings.xml index 171c092546e813..d562be6d686f5f 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values/strings.xml @@ -11,8 +11,7 @@ Disable Fast Refresh Disabling Fast Refresh because it requires a development bundle. Switching to development bundle in order to enable Fast Refresh. - Show Element Inspector - Hide Element Inspector + Toggle Element Inspector Show Perf Monitor Hide Perf Monitor Settings diff --git a/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-be/strings.xml b/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-be/strings.xml index f61f41054f4697..c3859037c9b9b1 100644 --- a/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-be/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-be/strings.xml @@ -6,4 +6,5 @@ Спасылка Відарыс Кнопка, відарыс + Меню diff --git a/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-kk/strings.xml b/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-kk/strings.xml index b8a8437b146fe5..278368ed76b950 100644 --- a/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-kk/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-kk/strings.xml @@ -7,6 +7,7 @@ Кескін Түйме, кескін Біріктірілген тізім + Мәзір қосулы өшірулі diff --git a/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-tg/strings.xml b/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-tg/strings.xml index 01bc8a89457279..6922f562e1ec4c 100644 --- a/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-tg/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/views/uimanager/values-tg/strings.xml @@ -7,6 +7,7 @@ Тасвир Тугма, тасвир Рӯйхати таркибӣ + Меню фаъол хомӯш diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/animated/NativeAnimatedNodeTraversalTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/animated/NativeAnimatedNodeTraversalTest.kt index b5eb4fc91d6c1e..96d15479cd901e 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/animated/NativeAnimatedNodeTraversalTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/animated/NativeAnimatedNodeTraversalTest.kt @@ -83,6 +83,7 @@ class NativeAnimatedNodeTraversalTest { whenever(catalystInstanceMock.getJSIModule(any(JSIModuleType::class.java))).thenAnswer { uiManagerMock } + whenever(reactApplicationContextMock.getFabricUIManager()).thenAnswer { uiManagerMock } whenever(catalystInstanceMock.getNativeModule(UIManagerModule::class.java)).thenAnswer { uiManagerMock } diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/runtime/ReactHostDelegateTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/runtime/ReactHostDelegateTest.kt index 33932b8a87bf34..0407c0ae127f25 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/runtime/ReactHostDelegateTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/runtime/ReactHostDelegateTest.kt @@ -34,13 +34,13 @@ class ReactHostDelegateTest { val jsBundleLoader: JSBundleLoader = Mockito.mock(JSBundleLoader::class.java) val turboModuleManagerDelegateBuilderMock: ReactPackageTurboModuleManagerDelegate.Builder = Mockito.mock(ReactPackageTurboModuleManagerDelegate.Builder::class.java) - val hermesInstance: JSEngineInstance = Mockito.mock(HermesInstance::class.java) + val hermesInstance: JSRuntimeFactory = Mockito.mock(HermesInstance::class.java) val jsMainModulePathMocked = "mockedJSMainModulePath" val delegate = DefaultReactHostDelegate( jsMainModulePath = jsMainModulePathMocked, jsBundleLoader = jsBundleLoader, - jsEngineInstance = hermesInstance, + jsRuntimeFactory = hermesInstance, turboModuleManagerDelegateBuilder = turboModuleManagerDelegateBuilderMock) assertThat(delegate.jsMainModulePath).isEqualTo(jsMainModulePathMocked) diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java deleted file mode 100644 index 2de130c9a5cc8e..00000000000000 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.uimanager; - -import static junit.framework.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyFloat; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -import android.util.DisplayMetrics; -import com.facebook.react.bridge.JavaOnlyMap; -import com.facebook.yoga.YogaAlign; -import com.facebook.yoga.YogaConstants; -import com.facebook.yoga.YogaFlexDirection; -import com.facebook.yoga.YogaJustify; -import com.facebook.yoga.YogaPositionType; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.mockito.stubbing.Answer; -import org.robolectric.RobolectricTestRunner; - -@RunWith(RobolectricTestRunner.class) -@Ignore // TODO T14964130 -public class LayoutPropertyApplicatorTest { - - @Before - public void setup() { - DisplayMetricsHolder.setWindowDisplayMetrics(new DisplayMetrics()); - DisplayMetricsHolder.setScreenDisplayMetrics(new DisplayMetrics()); - } - - @After - public void teardown() { - DisplayMetricsHolder.setWindowDisplayMetrics(null); - DisplayMetricsHolder.setScreenDisplayMetrics(null); - } - - public ReactStylesDiffMap buildStyles(Object... keysAndValues) { - return new ReactStylesDiffMap(JavaOnlyMap.of(keysAndValues)); - } - - @Test - public void testDimensions() { - LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode()); - ReactStylesDiffMap map = - spy(buildStyles("width", 10.0, "height", 10.0, "left", 10.0, "top", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setStyleWidth(anyFloat()); - verify(map).getFloat(eq("width"), anyFloat()); - verify(reactShadowNode).setStyleHeight(anyFloat()); - verify(map).getFloat(eq("height"), anyFloat()); - verify(reactShadowNode).setPosition(eq(Spacing.START), anyFloat()); - verify(map).getFloat(eq("left"), anyFloat()); - verify(reactShadowNode).setPosition(eq(Spacing.TOP), anyFloat()); - verify(map).getFloat(eq("top"), anyFloat()); - - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles()); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode, never()).setStyleWidth(anyFloat()); - verify(map, never()).getFloat(eq("width"), anyFloat()); - verify(reactShadowNode, never()).setStyleHeight(anyFloat()); - verify(map, never()).getFloat(eq("height"), anyFloat()); - verify(reactShadowNode, never()).setPosition(eq(Spacing.START), anyFloat()); - verify(map, never()).getFloat(eq("left"), anyFloat()); - verify(reactShadowNode, never()).setPosition(eq(Spacing.TOP), anyFloat()); - verify(map, never()).getFloat(eq("top"), anyFloat()); - } - - @Test - public void testFlex() { - LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode()); - ReactStylesDiffMap map = spy(buildStyles("flex", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setFlex(anyFloat()); - verify(map).getFloat("flex", 0.f); - - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles()); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode, never()).setFlex(anyFloat()); - verify(map, never()).getFloat("flex", 0.f); - } - - @Test - public void testPosition() { - LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode()); - ReactStylesDiffMap map = spy(buildStyles("position", "absolute", "bottom", 10.0, "right", 5.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setPosition(eq(Spacing.BOTTOM), anyFloat()); - verify(reactShadowNode).setPosition(eq(Spacing.END), anyFloat()); - verify(reactShadowNode).setPositionType(any(YogaPositionType.class)); - verify(map).getFloat("bottom", Float.NaN); - verify(map).getFloat("right", Float.NaN); - - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles()); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode, never()).setPosition(eq(Spacing.BOTTOM), anyFloat()); - verify(reactShadowNode, never()).setPosition(eq(Spacing.END), anyFloat()); - verify(reactShadowNode, never()).setPositionType(any(YogaPositionType.class)); - verify(map, never()).getFloat("bottom", Float.NaN); - verify(map, never()).getFloat("right", Float.NaN); - } - - @Test - public void testMargin() { - // margin - LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode()); - ReactStylesDiffMap map = spy(buildStyles("margin", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setMargin(eq(Spacing.ALL), anyFloat()); - verify(map).getFloat("margin", YogaConstants.UNDEFINED); - - // marginVertical - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("marginVertical", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setMargin(eq(Spacing.VERTICAL), anyFloat()); - verify(map).getFloat("marginVertical", YogaConstants.UNDEFINED); - - // marginHorizontal - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("marginHorizontal", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setMargin(eq(Spacing.HORIZONTAL), anyFloat()); - verify(map).getFloat("marginHorizontal", YogaConstants.UNDEFINED); - - // marginTop - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("marginTop", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setMargin(eq(Spacing.TOP), anyFloat()); - verify(map).getFloat("marginTop", YogaConstants.UNDEFINED); - - // marginBottom - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("marginBottom", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setMargin(eq(Spacing.BOTTOM), anyFloat()); - verify(map).getFloat("marginBottom", YogaConstants.UNDEFINED); - - // marginLeft - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("marginLeft", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setMargin(eq(Spacing.START), anyFloat()); - verify(map).getFloat("marginLeft", YogaConstants.UNDEFINED); - - // marginRight - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("marginRight", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setMargin(eq(Spacing.END), anyFloat()); - verify(map).getFloat("marginRight", YogaConstants.UNDEFINED); - - // no margin - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles()); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode, never()).setMargin(anyInt(), anyFloat()); - verify(map, never()).getFloat("margin", YogaConstants.UNDEFINED); - } - - @Test - public void testPadding() { - // padding - LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode()); - ReactStylesDiffMap map = spy(buildStyles("padding", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setPadding(eq(Spacing.ALL), anyFloat()); - verify(map).getFloat("padding", YogaConstants.UNDEFINED); - - // paddingVertical - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("paddingVertical", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setPadding(eq(Spacing.VERTICAL), anyFloat()); - verify(map).getFloat("paddingVertical", YogaConstants.UNDEFINED); - - // paddingHorizontal - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("paddingHorizontal", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setPadding(eq(Spacing.HORIZONTAL), anyFloat()); - verify(map).getFloat("paddingHorizontal", YogaConstants.UNDEFINED); - - // paddingTop - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("paddingTop", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setPadding(eq(Spacing.TOP), anyFloat()); - verify(map).getFloat("paddingTop", YogaConstants.UNDEFINED); - - // paddingBottom - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("paddingBottom", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setPadding(eq(Spacing.BOTTOM), anyFloat()); - verify(map).getFloat("paddingBottom", YogaConstants.UNDEFINED); - - // paddingLeft - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("paddingLeft", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setPadding(eq(Spacing.START), anyFloat()); - verify(map).getFloat("paddingLeft", YogaConstants.UNDEFINED); - - // paddingRight - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles("paddingRight", 10.0)); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setPadding(eq(Spacing.END), anyFloat()); - verify(map).getFloat("paddingRight", YogaConstants.UNDEFINED); - - // no padding - reactShadowNode = spy(new LayoutShadowNode()); - map = spy(buildStyles()); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode, never()).setPadding(anyInt(), anyFloat()); - verify(map, never()).getFloat("padding", YogaConstants.UNDEFINED); - } - - @Test - public void testEnumerations() { - LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode()); - ReactStylesDiffMap map = - buildStyles( - "flexDirection", - "column", - "alignSelf", - "stretch", - "alignItems", - "center", - "justifyContent", - "space_between", - "position", - "relative"); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setFlexDirection(YogaFlexDirection.COLUMN); - verify(reactShadowNode).setAlignSelf(YogaAlign.STRETCH); - verify(reactShadowNode).setAlignItems(YogaAlign.CENTER); - verify(reactShadowNode).setJustifyContent(YogaJustify.SPACE_BETWEEN); - verify(reactShadowNode).setPositionType(YogaPositionType.RELATIVE); - - reactShadowNode = spy(new LayoutShadowNode()); - map = buildStyles(); - reactShadowNode.updateProperties(map); - - verify(reactShadowNode, never()).setFlexDirection(any(YogaFlexDirection.class)); - verify(reactShadowNode, never()).setAlignSelf(any(YogaAlign.class)); - verify(reactShadowNode, never()).setAlignItems(any(YogaAlign.class)); - verify(reactShadowNode, never()).setJustifyContent(any(YogaJustify.class)); - verify(reactShadowNode, never()).setPositionType(any(YogaPositionType.class)); - } - - @Test - public void testPropertiesResetToDefault() { - DisplayMetrics displayMetrics = new DisplayMetrics(); - displayMetrics.density = 1.0f; - DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics); - - LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode()); - ReactStylesDiffMap map = - buildStyles( - "width", - 10.0, - "height", - 10.0, - "left", - 10.0, - "top", - 10.0, - "flex", - 1.0, - "padding", - 10.0, - "marginLeft", - 10.0, - "borderTopWidth", - 10.0, - "flexDirection", - "row", - "alignSelf", - "stretch", - "alignItems", - "center", - "justifyContent", - "space_between", - "position", - "absolute"); - - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setStyleWidth(10.f); - verify(reactShadowNode).setStyleHeight(10.f); - verify(reactShadowNode).setPosition(Spacing.START, 10.f); - verify(reactShadowNode).setPosition(Spacing.TOP, 10.f); - verify(reactShadowNode).setFlex(1.0f); - verify(reactShadowNode).setPadding(Spacing.ALL, 10.f); - verify(reactShadowNode).setMargin(Spacing.START, 10.f); - verify(reactShadowNode).setBorder(Spacing.TOP, 10.f); - verify(reactShadowNode).setFlexDirection(YogaFlexDirection.ROW); - verify(reactShadowNode).setAlignSelf(YogaAlign.STRETCH); - verify(reactShadowNode).setAlignItems(YogaAlign.CENTER); - verify(reactShadowNode).setJustifyContent(YogaJustify.SPACE_BETWEEN); - verify(reactShadowNode).setPositionType(YogaPositionType.ABSOLUTE); - - map = - buildStyles( - "width", - null, - "height", - null, - "left", - null, - "top", - null, - "flex", - null, - "padding", - null, - "marginLeft", - null, - "borderTopWidth", - null, - "flexDirection", - null, - "alignSelf", - null, - "alignItems", - null, - "justifyContent", - null, - "position", - null); - - reset(reactShadowNode); - reactShadowNode.updateProperties(map); - verify(reactShadowNode).setStyleWidth(YogaConstants.UNDEFINED); - verify(reactShadowNode).setStyleHeight(YogaConstants.UNDEFINED); - verify(reactShadowNode).setPosition(Spacing.START, YogaConstants.UNDEFINED); - verify(reactShadowNode).setPosition(Spacing.TOP, YogaConstants.UNDEFINED); - verify(reactShadowNode).setFlex(0.f); - verify(reactShadowNode).setPadding(Spacing.ALL, YogaConstants.UNDEFINED); - verify(reactShadowNode).setMargin(Spacing.START, YogaConstants.UNDEFINED); - verify(reactShadowNode).setBorder(Spacing.TOP, YogaConstants.UNDEFINED); - verify(reactShadowNode).setFlexDirection(YogaFlexDirection.COLUMN); - verify(reactShadowNode).setAlignSelf(YogaAlign.AUTO); - verify(reactShadowNode).setAlignItems(YogaAlign.STRETCH); - verify(reactShadowNode).setJustifyContent(YogaJustify.FLEX_START); - verify(reactShadowNode).setPositionType(YogaPositionType.RELATIVE); - } - - @Test - public void testSettingDefaultStyleValues() { - MockedStatic pixelUtil = mockStatic(PixelUtil.class); - pixelUtil - .when(() -> PixelUtil.toPixelFromDIP(anyFloat())) - .thenAnswer( - (Answer) - invocation -> { - Object[] args = invocation.getArguments(); - return (Float) args[0]; - }); - - LayoutShadowNode[] nodes = new LayoutShadowNode[7]; - for (int idx = 0; idx < nodes.length; idx++) { - nodes[idx] = new LayoutShadowNode(); - nodes[idx].setDefaultPadding(Spacing.START, 15); - nodes[idx].setDefaultPadding(Spacing.TOP, 25); - nodes[idx].setDefaultPadding(Spacing.END, 35); - nodes[idx].setDefaultPadding(Spacing.BOTTOM, 45); - } - - ReactStylesDiffMap[] mapNodes = new ReactStylesDiffMap[7]; - mapNodes[0] = buildStyles("paddingLeft", 10.0, "paddingHorizontal", 5.0); - mapNodes[1] = buildStyles("padding", 10.0, "paddingTop", 5.0); - mapNodes[2] = buildStyles("paddingLeft", 10.0, "paddingVertical", 5.0); - mapNodes[3] = buildStyles("paddingBottom", 10.0, "paddingHorizontal", 5.0); - mapNodes[4] = buildStyles("padding", null, "paddingTop", 5.0); - mapNodes[5] = - buildStyles("paddingRight", 10.0, "paddingHorizontal", null, "paddingVertical", 7.0); - mapNodes[6] = buildStyles("margin", 5.0); - - for (int idx = 0; idx < nodes.length; idx++) { - nodes[idx].updateProperties(mapNodes[idx]); - } - - assertEquals(10.0, nodes[0].getPadding(Spacing.START), .0001); - assertEquals(25.0, nodes[0].getPadding(Spacing.TOP), .0001); - assertEquals(5.0, nodes[0].getPadding(Spacing.END), .0001); - assertEquals(45.0, nodes[0].getPadding(Spacing.BOTTOM), .0001); - - assertEquals(10.0, nodes[1].getPadding(Spacing.START), .0001); - assertEquals(5.0, nodes[1].getPadding(Spacing.TOP), .0001); - assertEquals(10.0, nodes[1].getPadding(Spacing.END), .0001); - assertEquals(10.0, nodes[1].getPadding(Spacing.BOTTOM), .0001); - - assertEquals(10.0, nodes[2].getPadding(Spacing.START), .0001); - assertEquals(5.0, nodes[2].getPadding(Spacing.TOP), .0001); - assertEquals(35.0, nodes[2].getPadding(Spacing.END), .0001); - assertEquals(5.0, nodes[2].getPadding(Spacing.BOTTOM), .0001); - - assertEquals(5.0, nodes[3].getPadding(Spacing.START), .0001); - assertEquals(25.0, nodes[3].getPadding(Spacing.TOP), .0001); - assertEquals(5.0, nodes[3].getPadding(Spacing.END), .0001); - assertEquals(10.0, nodes[3].getPadding(Spacing.BOTTOM), .0001); - - assertEquals(15.0, nodes[4].getPadding(Spacing.START), .0001); - assertEquals(5.0, nodes[4].getPadding(Spacing.TOP), .0001); - assertEquals(35.0, nodes[4].getPadding(Spacing.END), .0001); - assertEquals(45.0, nodes[4].getPadding(Spacing.BOTTOM), .0001); - - assertEquals(15.0, nodes[5].getPadding(Spacing.START), .0001); - assertEquals(7.0, nodes[5].getPadding(Spacing.TOP), .0001); - assertEquals(10.0, nodes[5].getPadding(Spacing.END), .0001); - assertEquals(7.0, nodes[5].getPadding(Spacing.BOTTOM), .0001); - - assertEquals(15.0, nodes[6].getPadding(Spacing.START), .0001); - assertEquals(25.0, nodes[6].getPadding(Spacing.TOP), .0001); - assertEquals(35.0, nodes[6].getPadding(Spacing.END), .0001); - assertEquals(45.0, nodes[6].getPadding(Spacing.BOTTOM), .0001); - } -} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.kt new file mode 100644 index 00000000000000..5f83847bd54109 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.kt @@ -0,0 +1,464 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.uimanager + +import android.util.DisplayMetrics +import com.facebook.react.bridge.JavaOnlyMap +import com.facebook.react.uimanager.Spacing.* +import com.facebook.yoga.YogaAlign +import com.facebook.yoga.YogaConstants +import com.facebook.yoga.YogaFlexDirection +import com.facebook.yoga.YogaJustify +import com.facebook.yoga.YogaPositionType +import org.junit.After +import org.junit.Assert.* +import org.junit.Before +import org.junit.Ignore +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyFloat +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito.mockStatic +import org.mockito.Mockito.never +import org.mockito.Mockito.reset +import org.mockito.Mockito.spy +import org.mockito.Mockito.verify +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +@Ignore +class LayoutPropertyApplicatorTest { + @Before + fun setup() { + DisplayMetricsHolder.setWindowDisplayMetrics(DisplayMetrics()) + DisplayMetricsHolder.setScreenDisplayMetrics(DisplayMetrics()) + } + + @After + fun teardown() { + DisplayMetricsHolder.setWindowDisplayMetrics(null) + DisplayMetricsHolder.setScreenDisplayMetrics(null) + } + + private fun buildStyles(vararg keysAndValues: Any?): ReactStylesDiffMap { + return ReactStylesDiffMap(JavaOnlyMap.of(*keysAndValues)) + } + + @Test + fun testDimensions() { + var reactShadowNode = spy(LayoutShadowNode()) + var map = spy(buildStyles("width", 10.0f, "height", 10.0f, "left", 10.0f, "top", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setStyleWidth(anyFloat()) + verify(map).getFloat(eq("width"), anyFloat()) + verify(reactShadowNode).setStyleHeight(anyFloat()) + verify(map).getFloat(eq("height"), anyFloat()) + verify(reactShadowNode).setPosition(eq(START), anyFloat()) + verify(map).getFloat(eq("left"), anyFloat()) + verify(reactShadowNode).setPosition(eq(TOP), anyFloat()) + verify(map).getFloat(eq("top"), anyFloat()) + + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles()) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode, never()).setStyleWidth(anyFloat()) + verify(map, never()).getFloat(eq("width"), anyFloat()) + verify(reactShadowNode, never()).setStyleHeight(anyFloat()) + verify(map, never()).getFloat(eq("height"), anyFloat()) + verify(reactShadowNode, never()).setPosition(eq(START), anyFloat()) + verify(map, never()).getFloat(eq("left"), anyFloat()) + verify(reactShadowNode, never()).setPosition(eq(TOP), anyFloat()) + verify(map, never()).getFloat(eq("top"), anyFloat()) + } + + @Test + fun testFlex() { + var reactShadowNode = spy(LayoutShadowNode()) + var map = spy(buildStyles("flex", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).flex = anyFloat() + verify(map).getFloat("flex", 0.0f) + + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles()) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode, never()).flex = anyFloat() + verify(map, never()).getFloat("flex", 0.0f) + } + + @Test + fun testPosition() { + var reactShadowNode = spy(LayoutShadowNode()) + var map = spy(buildStyles("position", "absolute", "bottom", 10.0f, "right", 5.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setPosition(eq(BOTTOM), anyFloat()) + verify(reactShadowNode).setPosition(eq(END), anyFloat()) + verify(reactShadowNode).setPositionType(any(YogaPositionType::class.java)) + verify(map).getFloat("bottom", Float.NaN) + verify(map).getFloat("right", Float.NaN) + + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles()) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode, never()).setPosition(eq(BOTTOM), anyFloat()) + verify(reactShadowNode, never()).setPosition(eq(END), anyFloat()) + verify(reactShadowNode, never()).setPositionType(any(YogaPositionType::class.java)) + verify(map, never()).getFloat("bottom", Float.NaN) + verify(map, never()).getFloat("right", Float.NaN) + } + + @Test + fun testMargin() { + // margin + var reactShadowNode = spy(LayoutShadowNode()) + var map = spy(buildStyles("margin", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setMargin(eq(ALL), anyFloat()) + verify(map).getFloat("margin", YogaConstants.UNDEFINED) + + // marginVertical + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("marginVertical", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setMargin(eq(VERTICAL), anyFloat()) + verify(map).getFloat("marginVertical", YogaConstants.UNDEFINED) + + // marginHorizontal + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("marginHorizontal", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setMargin(eq(HORIZONTAL), anyFloat()) + verify(map).getFloat("marginHorizontal", YogaConstants.UNDEFINED) + + // marginTop + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("marginTop", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setMargin(eq(TOP), anyFloat()) + verify(map).getFloat("marginTop", YogaConstants.UNDEFINED) + + // marginBottom + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("marginBottom", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setMargin(eq(BOTTOM), anyFloat()) + verify(map).getFloat("marginBottom", YogaConstants.UNDEFINED) + + // marginLeft + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("marginLeft", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setMargin(eq(START), anyFloat()) + verify(map).getFloat("marginLeft", YogaConstants.UNDEFINED) + + // marginRight + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("marginRight", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setMargin(eq(END), anyFloat()) + verify(map).getFloat("marginRight", YogaConstants.UNDEFINED) + + // no margin + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles()) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode, never()).setMargin(anyInt(), anyFloat()) + verify(map, never()).getFloat("margin", YogaConstants.UNDEFINED) + } + + @Test + fun testPadding() { + // padding + var reactShadowNode = spy(LayoutShadowNode()) + var map = spy(buildStyles("padding", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setPadding(eq(ALL), anyFloat()) + verify(map).getFloat("padding", YogaConstants.UNDEFINED) + + // paddingVertical + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("paddingVertical", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setPadding(eq(VERTICAL), anyFloat()) + verify(map).getFloat("paddingVertical", YogaConstants.UNDEFINED) + + // paddingHorizontal + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("paddingHorizontal", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setPadding(eq(HORIZONTAL), anyFloat()) + verify(map).getFloat("paddingHorizontal", YogaConstants.UNDEFINED) + + // paddingTop + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("paddingTop", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setPadding(eq(TOP), anyFloat()) + verify(map).getFloat("paddingTop", YogaConstants.UNDEFINED) + + // paddingBottom + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("paddingBottom", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setPadding(eq(BOTTOM), anyFloat()) + verify(map).getFloat("paddingBottom", YogaConstants.UNDEFINED) + + // paddingLeft + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("paddingLeft", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setPadding(eq(START), anyFloat()) + verify(map).getFloat("paddingLeft", YogaConstants.UNDEFINED) + + // paddingRight + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles("paddingRight", 10.0f)) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setPadding(eq(END), anyFloat()) + verify(map).getFloat("paddingRight", YogaConstants.UNDEFINED) + + // no padding + reactShadowNode = spy(LayoutShadowNode()) + map = spy(buildStyles()) + + reactShadowNode.updateProperties(map) + verify(reactShadowNode, never()).setPadding(anyInt(), anyFloat()) + verify(map, never()).getFloat("padding", YogaConstants.UNDEFINED) + } + + @Test + fun testEnumerations() { + var reactShadowNode = spy(LayoutShadowNode()) + var map = + buildStyles( + "flexDirection", + "column", + "alignSelf", + "stretch", + "alignItems", + "center", + "justifyContent", + "space_between", + "position", + "relative") + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setFlexDirection(YogaFlexDirection.COLUMN) + verify(reactShadowNode).setAlignSelf(YogaAlign.STRETCH) + verify(reactShadowNode).setAlignItems(YogaAlign.CENTER) + verify(reactShadowNode).setJustifyContent(YogaJustify.SPACE_BETWEEN) + verify(reactShadowNode).setPositionType(YogaPositionType.RELATIVE) + + reactShadowNode = spy(LayoutShadowNode()) + map = buildStyles() + reactShadowNode.updateProperties(map) + + verify(reactShadowNode, never()).setFlexDirection(any(YogaFlexDirection::class.java)) + verify(reactShadowNode, never()).setAlignSelf(any(YogaAlign::class.java)) + verify(reactShadowNode, never()).setAlignItems(any(YogaAlign::class.java)) + verify(reactShadowNode, never()).setJustifyContent(any(YogaJustify::class.java)) + verify(reactShadowNode, never()).setPositionType(any(YogaPositionType::class.java)) + } + + @Test + fun testPropertiesResetToDefault() { + val displayMetrics = DisplayMetrics() + displayMetrics.density = 1.0f + DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics) + + val reactShadowNode = spy(LayoutShadowNode()) + var map = + buildStyles( + "width", + 10.0f, + "height", + 10.0f, + "left", + 10.0f, + "top", + 10.0f, + "flex", + 1.0f, + "padding", + 10.0f, + "marginLeft", + 10.0f, + "borderTopWidth", + 10.0f, + "flexDirection", + "row", + "alignSelf", + "stretch", + "alignItems", + "center", + "justifyContent", + "space_between", + "position", + "absolute") + + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setStyleWidth(10.0f) + verify(reactShadowNode).setStyleHeight(10.0f) + verify(reactShadowNode).setPosition(START, 10.0f) + verify(reactShadowNode).setPosition(TOP, 10.0f) + verify(reactShadowNode).flex = 1.0f + verify(reactShadowNode).setPadding(ALL, 10.0f) + verify(reactShadowNode).setMargin(START, 10.0f) + verify(reactShadowNode).setBorder(TOP, 10.0f) + verify(reactShadowNode).setFlexDirection(YogaFlexDirection.ROW) + verify(reactShadowNode).setAlignSelf(YogaAlign.STRETCH) + verify(reactShadowNode).setAlignItems(YogaAlign.CENTER) + verify(reactShadowNode).setJustifyContent(YogaJustify.SPACE_BETWEEN) + verify(reactShadowNode).setPositionType(YogaPositionType.ABSOLUTE) + + map = + buildStyles( + "width", + null, + "height", + null, + "left", + null, + "top", + null, + "flex", + null, + "padding", + null, + "marginLeft", + null, + "borderTopWidth", + null, + "flexDirection", + null, + "alignSelf", + null, + "alignItems", + null, + "justifyContent", + null, + "position", + null) + + reset(reactShadowNode) + reactShadowNode.updateProperties(map) + verify(reactShadowNode).setStyleWidth(YogaConstants.UNDEFINED) + verify(reactShadowNode).setStyleHeight(YogaConstants.UNDEFINED) + verify(reactShadowNode).setPosition(START, YogaConstants.UNDEFINED) + verify(reactShadowNode).setPosition(TOP, YogaConstants.UNDEFINED) + verify(reactShadowNode).flex = 0.0f + verify(reactShadowNode).setPadding(ALL, YogaConstants.UNDEFINED) + verify(reactShadowNode).setMargin(START, YogaConstants.UNDEFINED) + verify(reactShadowNode).setBorder(TOP, YogaConstants.UNDEFINED) + verify(reactShadowNode).setFlexDirection(YogaFlexDirection.COLUMN) + verify(reactShadowNode).setAlignSelf(YogaAlign.AUTO) + verify(reactShadowNode).setAlignItems(YogaAlign.STRETCH) + verify(reactShadowNode).setJustifyContent(YogaJustify.FLEX_START) + verify(reactShadowNode).setPositionType(YogaPositionType.RELATIVE) + } + + @Test + fun testSettingDefaultStyleValues() { + val pixelUtil = mockStatic(PixelUtil::class.java) + pixelUtil + .`when` { PixelUtil.toPixelFromDIP(anyFloat()) } + .thenAnswer { + return@thenAnswer it.arguments[0] + } + val nodesSize = 7 + val nodes = + Array(nodesSize) { + val node = LayoutShadowNode() + node.setDefaultPadding(START, 15.0f) + node.setDefaultPadding(TOP, 25.0f) + node.setDefaultPadding(END, 35.0f) + node.setDefaultPadding(BOTTOM, 45.0f) + node + } + + val mapNodes = + Array(nodesSize) { + when (it) { + 0 -> buildStyles("paddingLeft", 10.0f, "paddingHorizontal", 5.0f) + 1 -> buildStyles("padding", 10.0f, "paddingTop", 5.0f) + 2 -> buildStyles("paddingLeft", 10.0f, "paddingVertical", 5.0f) + 3 -> buildStyles("paddingBottom", 10.0f, "paddingHorizontal", 5.0f) + 4 -> buildStyles("padding", null, "paddingTop", 5.0f) + 5 -> + buildStyles( + "paddingRight", 10.0f, "paddingHorizontal", null, "paddingVertical", 7.0f) + 6 -> buildStyles("margin", 5.0f) + else -> { + null + } + } + } + + for (i in 0..nodesSize) { + nodes[i].updateProperties(mapNodes[i]) + } + + assertEquals(10.0f, nodes[0].getPadding(START), .0001f) + assertEquals(25.0f, nodes[0].getPadding(TOP), .0001f) + assertEquals(5.0f, nodes[0].getPadding(END), .0001f) + assertEquals(45.0f, nodes[0].getPadding(BOTTOM), .0001f) + + assertEquals(10.0f, nodes[1].getPadding(START), .0001f) + assertEquals(5.0f, nodes[1].getPadding(TOP), .0001f) + assertEquals(10.0f, nodes[1].getPadding(END), .0001f) + assertEquals(10.0f, nodes[1].getPadding(BOTTOM), .0001f) + + assertEquals(10.0f, nodes[2].getPadding(START), .0001f) + assertEquals(5.0f, nodes[2].getPadding(TOP), .0001f) + assertEquals(35.0f, nodes[2].getPadding(END), .0001f) + assertEquals(5.0f, nodes[2].getPadding(BOTTOM), .0001f) + + assertEquals(5.0f, nodes[3].getPadding(START), .0001f) + assertEquals(25.0f, nodes[3].getPadding(TOP), .0001f) + assertEquals(5.0f, nodes[3].getPadding(END), .0001f) + assertEquals(10.0f, nodes[3].getPadding(BOTTOM), .0001f) + + assertEquals(15.0f, nodes[4].getPadding(START), .0001f) + assertEquals(5.0f, nodes[4].getPadding(TOP), .0001f) + assertEquals(35.0f, nodes[4].getPadding(END), .0001f) + assertEquals(45.0f, nodes[4].getPadding(BOTTOM), .0001f) + + assertEquals(15.0f, nodes[5].getPadding(START), .0001f) + assertEquals(7.0f, nodes[5].getPadding(TOP), .0001f) + assertEquals(10.0f, nodes[5].getPadding(END), .0001f) + assertEquals(7.0f, nodes[5].getPadding(BOTTOM), .0001f) + + assertEquals(15.0f, nodes[6].getPadding(START), .0001f) + assertEquals(25.0f, nodes[6].getPadding(TOP), .0001f) + assertEquals(35.0f, nodes[6].getPadding(END), .0001f) + assertEquals(45.0f, nodes[6].getPadding(BOTTOM), .0001f) + } +} diff --git a/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/Exported/RCTDeprecation.h b/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/Exported/RCTDeprecation.h new file mode 100644 index 00000000000000..dc7b92b3d88036 --- /dev/null +++ b/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/Exported/RCTDeprecation.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef RCT_DEPRECATED_DECLARATIONS +#define RCT_DEPRECATED_DECLARATIONS 0 +#endif + +#if RCT_DEPRECATED_DECLARATIONS +#define RCT_DEPRECATED __attribute__((deprecated)) +#else +#define RCT_DEPRECATED +#endif diff --git a/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/RCTDeprecation.m b/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/RCTDeprecation.m new file mode 100644 index 00000000000000..cc1cbc7cf3730a --- /dev/null +++ b/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/RCTDeprecation.m @@ -0,0 +1,8 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// Dummy file to make RCTDeprecation a valid framework. diff --git a/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/RCTDeprecation.podspec b/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/RCTDeprecation.podspec new file mode 100644 index 00000000000000..afd7d4eeb1c97f --- /dev/null +++ b/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/RCTDeprecation.podspec @@ -0,0 +1,25 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "..", "..", "..", "..", "package.json"))) +version = package['version'] + +Pod::Spec.new do |s| + s.name = "RCTDeprecation" + s.version = version + s.author = "Meta Platforms, Inc. and its affiliates" + s.license = package["license"] + s.homepage = "https://reactnative.dev/" + s.source = { :git => 'https://github.com/facebook/react-native.git', :tag => 'v#{version}' } + s.summary = "Macros for marking APIs as deprecated" + s.source_files = ["Exported/*.h", "RCTDeprecation.m"] + s.pod_target_xcconfig = { + "DEFINES_MODULE" => "YES", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++20" + } + s.compiler_flags = "-Wnullable-to-nonnull-conversion -Wnullability-completeness" + end diff --git a/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/README.md b/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/README.md new file mode 100644 index 00000000000000..9f0d87aaa6d759 --- /dev/null +++ b/packages/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation/README.md @@ -0,0 +1 @@ +RCTDeprecation contains C macros to identify deprecated APIs at build-time. diff --git a/packages/react-native/ReactApple/Libraries/RCTFoundation/README.md b/packages/react-native/ReactApple/Libraries/RCTFoundation/README.md new file mode 100644 index 00000000000000..b5bdb2bf6f040d --- /dev/null +++ b/packages/react-native/ReactApple/Libraries/RCTFoundation/README.md @@ -0,0 +1,12 @@ +# RCTFoundation + +RCTFoundation is a collection of lightweight utility libraries. + +Rules for RCTFoundation libraries: +- They must only depend on other RCTFoundation libraries. +- Headers cannot contain C++. +- They have modular set to true in BUCK. +- They have complete_nullability set to true. +- They have enabled Clang compiler warnings. +- They have documentation. +- They have unit tests. diff --git a/packages/react-native/ReactApple/README.md b/packages/react-native/ReactApple/README.md new file mode 100644 index 00000000000000..faafcb1dabb8de --- /dev/null +++ b/packages/react-native/ReactApple/README.md @@ -0,0 +1,5 @@ +# ReactApple + +ReactApple contains code to ship React Native apps to Apple devices. The dominant language is Objective-C. + +New libraries built with Apple frameworks or intended to ship to Apple devices should live in this directory. diff --git a/packages/react-native/ReactCommon/React-Fabric.podspec b/packages/react-native/ReactCommon/React-Fabric.podspec index d4d6eb87d43164..c9ee015fddcd13 100644 --- a/packages/react-native/ReactCommon/React-Fabric.podspec +++ b/packages/react-native/ReactCommon/React-Fabric.podspec @@ -97,7 +97,7 @@ Pod::Spec.new do |s| if ENV['USE_FRAMEWORKS'] header_search_path = header_search_path + [ "\"$(PODS_TARGET_SRCROOT)/react/renderer/textlayoutmanager/platform/ios\"", - "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/textinput/iostextinput\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/textinput/platform/ios\"", "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/view/platform/cxx\"", ] end @@ -115,7 +115,7 @@ Pod::Spec.new do |s| s.subspec "componentregistry" do |ss| ss.dependency folly_dep_name, folly_version ss.compiler_flags = folly_compiler_flags - ss.source_files = "react/renderer/componentregistry/**/*.{m,mm,cpp,h}" + ss.source_files = "react/renderer/componentregistry/*.{m,mm,cpp,h}" ss.header_dir = "react/renderer/componentregistry" end @@ -198,8 +198,7 @@ Pod::Spec.new do |s| ss.subspec "textinput" do |sss| sss.dependency folly_dep_name, folly_version sss.compiler_flags = folly_compiler_flags - sss.source_files = "react/renderer/components/textinput/iostextinput/**/*.{m,mm,cpp,h}" - sss.exclude_files = "react/renderer/components/textinput/iostextinput/tests" + sss.source_files = "react/renderer/components/textinput/platform/ios/**/*.{m,mm,cpp,h}" sss.header_dir = "react/renderer/components/iostextinput" end diff --git a/packages/react-native/ReactCommon/React-FabricImage.podspec b/packages/react-native/ReactCommon/React-FabricImage.podspec index 8d645c329fcb26..a32f07c8b9207a 100644 --- a/packages/react-native/ReactCommon/React-FabricImage.podspec +++ b/packages/react-native/ReactCommon/React-FabricImage.podspec @@ -35,7 +35,7 @@ if ENV['USE_FRAMEWORKS'] header_search_path = header_search_path + [ "\"$(PODS_TARGET_SRCROOT)\"", "\"$(PODS_TARGET_SRCROOT)/react/renderer/textlayoutmanager/platform/ios\"", - "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/textinput/iostextinput\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/textinput/platform/ios\"", # "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-Codegen/React_Codegen.framework/Headers\"", ] end diff --git a/packages/react-native/ReactCommon/React-rncore.podspec b/packages/react-native/ReactCommon/React-rncore.podspec index a4532697403bcb..06b8bc7feff1b7 100644 --- a/packages/react-native/ReactCommon/React-rncore.podspec +++ b/packages/react-native/ReactCommon/React-rncore.podspec @@ -49,13 +49,4 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { "USE_HEADERMAP" => "YES", "HEADER_SEARCH_PATHS" => header_search_paths.join(' '), "CLANG_CXX_LANGUAGE_STANDARD" => "c++20" } - - - use_react_native_codegen!(s, { - :react_native_path => react_native_sources_path, - :js_srcs_dir => "#{react_native_sources_path}/Libraries", - :library_name => "rncore", - :library_type => "components", - :output_dir => "#{react_native_dependency_path}/ReactCommon" - }) end diff --git a/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp b/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp index e9059dac7137c8..86c3a03c9df5bf 100644 --- a/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp +++ b/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp @@ -53,9 +53,13 @@ void StartupLogger::logStartupEvent( double markerTime) { switch (markerId) { case ReactMarkerId::APP_STARTUP_START: - if (std::isnan(appStartupStartTime)) { - appStartupStartTime = markerTime; + if (!std::isnan(appStartupStartTime)) { + // We had a startup start time, which indicates a warm start (user + // closed the app and start again). In this case we need to invalidate + // all other startup timings. + reset(); } + appStartupStartTime = markerTime; return; case ReactMarkerId::APP_STARTUP_STOP: @@ -93,6 +97,15 @@ void StartupLogger::logStartupEvent( } } +void StartupLogger::reset() { + appStartupStartTime = std::nan(""); + appStartupEndTime = std::nan(""); + initReactRuntimeStartTime = std::nan(""); + initReactRuntimeEndTime = std::nan(""); + runJSBundleStartTime = std::nan(""); + runJSBundleEndTime = std::nan(""); +} + double StartupLogger::getAppStartupStartTime() { return appStartupStartTime; } diff --git a/packages/react-native/ReactCommon/cxxreact/ReactMarker.h b/packages/react-native/ReactCommon/cxxreact/ReactMarker.h index 8d3a532e2c4e0d..e50746780d4867 100644 --- a/packages/react-native/ReactCommon/cxxreact/ReactMarker.h +++ b/packages/react-native/ReactCommon/cxxreact/ReactMarker.h @@ -74,6 +74,7 @@ class RN_EXPORT StartupLogger { static StartupLogger& getInstance(); void logStartupEvent(const ReactMarkerId markerName, double markerTime); + void reset(); double getAppStartupStartTime(); double getInitReactRuntimeStartTime(); double getInitReactRuntimeEndTime(); diff --git a/packages/react-native/ReactCommon/jsc/CMakeLists.txt b/packages/react-native/ReactCommon/jsc/CMakeLists.txt index c5c17fb4048da8..d71b289679bcfa 100644 --- a/packages/react-native/ReactCommon/jsc/CMakeLists.txt +++ b/packages/react-native/ReactCommon/jsc/CMakeLists.txt @@ -30,10 +30,6 @@ target_link_libraries(jscruntime jsi glog) -# TODO: Remove this flag when ready. -# Android has this enabled by default, but the flag is still needed for iOS. -target_compile_options(jscruntime PRIVATE -DRN_FABRIC_ENABLED) - if(NOT ${CMAKE_BUILD_TYPE} MATCHES Debug) target_compile_options(jscruntime PRIVATE -DNDEBUG) endif() diff --git a/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp b/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp index 34f43c0c08e9a0..c42d4f3008e4a6 100644 --- a/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp +++ b/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp @@ -233,6 +233,7 @@ class JSCRuntime : public jsi::Runtime { bool strictEquals(const jsi::String& a, const jsi::String& b) const override; bool strictEquals(const jsi::Object& a, const jsi::Object& b) const override; bool instanceOf(const jsi::Object& o, const jsi::Function& f) override; + void setExternalMemoryPressure(const jsi::Object&, size_t) override; private: // Basically convenience casts @@ -240,10 +241,7 @@ class JSCRuntime : public jsi::Runtime { static JSStringRef stringRef(const jsi::String& str); static JSStringRef stringRef(const jsi::PropNameID& sym); static JSObjectRef objectRef(const jsi::Object& obj); - -#ifdef RN_FABRIC_ENABLED static JSObjectRef objectRef(const jsi::WeakObject& obj); -#endif // Factory methods for creating String/Object jsi::Symbol createSymbol(JSValueRef symbolRef) const; @@ -1065,23 +1063,15 @@ jsi::Array JSCRuntime::getPropertyNames(const jsi::Object& obj) { } jsi::WeakObject JSCRuntime::createWeakObject(const jsi::Object& obj) { -#ifdef RN_FABRIC_ENABLED // TODO: revisit this implementation JSObjectRef objRef = objectRef(obj); return make(makeObjectValue(objRef)); -#else - throw std::logic_error("Not implemented"); -#endif } jsi::Value JSCRuntime::lockWeakObject(const jsi::WeakObject& obj) { -#ifdef RN_FABRIC_ENABLED // TODO: revisit this implementation JSObjectRef objRef = objectRef(obj); return jsi::Value(createObject(objRef)); -#else - throw std::logic_error("Not implemented"); -#endif } jsi::Array JSCRuntime::createArray(size_t length) { @@ -1403,6 +1393,8 @@ bool JSCRuntime::instanceOf(const jsi::Object& o, const jsi::Function& f) { return res; } +void JSCRuntime::setExternalMemoryPressure(const jsi::Object&, size_t) {} + jsi::Runtime::PointerValue* JSCRuntime::makeSymbolValue( JSValueRef symbolRef) const { #ifndef NDEBUG @@ -1527,12 +1519,10 @@ JSObjectRef JSCRuntime::objectRef(const jsi::Object& obj) { return static_cast(getPointerValue(obj))->obj_; } -#ifdef RN_FABRIC_ENABLED JSObjectRef JSCRuntime::objectRef(const jsi::WeakObject& obj) { // TODO: revisit this implementation return static_cast(getPointerValue(obj))->obj_; } -#endif void JSCRuntime::checkException(JSValueRef exc) { if (JSC_UNLIKELY(exc)) { diff --git a/packages/react-native/ReactCommon/jsc/React-jsc.podspec b/packages/react-native/ReactCommon/jsc/React-jsc.podspec index ee9cf096e7a961..6239621c6a8c64 100644 --- a/packages/react-native/ReactCommon/jsc/React-jsc.podspec +++ b/packages/react-native/ReactCommon/jsc/React-jsc.podspec @@ -32,6 +32,6 @@ Pod::Spec.new do |s| s.dependency "React-jsi", version s.subspec "Fabric" do |ss| - ss.pod_target_xcconfig = { "OTHER_CFLAGS" => "$(inherited) -DRN_FABRIC_ENABLED" } + ss.pod_target_xcconfig = { "OTHER_CFLAGS" => "$(inherited)" } end end diff --git a/packages/react-native/ReactCommon/jsi/jsi/JSIDynamic.cpp b/packages/react-native/ReactCommon/jsi/jsi/JSIDynamic.cpp index 02f112c0e0ca09..5a2d38d9dd3915 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/JSIDynamic.cpp +++ b/packages/react-native/ReactCommon/jsi/jsi/JSIDynamic.cpp @@ -150,7 +150,10 @@ void dynamicFromValueShallow( } // namespace -folly::dynamic dynamicFromValue(Runtime& runtime, const Value& valueInput) { +folly::dynamic dynamicFromValue( + Runtime& runtime, + const Value& valueInput, + std::function filterObjectKeys) { std::vector stack; folly::dynamic ret; @@ -182,13 +185,17 @@ folly::dynamic dynamicFromValue(Runtime& runtime, const Value& valueInput) { if (prop.isUndefined()) { continue; } + auto nameStr = name.utf8(runtime); + if (filterObjectKeys && filterObjectKeys(nameStr)) { + continue; + } // The JSC conversion uses JSON.stringify, which substitutes // null for a function, so we do the same here. Just dropping // the pair might also work, but would require more testing. if (prop.isObject() && prop.getObject(runtime).isFunction(runtime)) { prop = Value::null(); } - props.emplace_back(name.utf8(runtime), std::move(prop)); + props.emplace_back(std::move(nameStr), std::move(prop)); top.dyn->insert(props.back().first, nullptr); } for (const auto& prop : props) { diff --git a/packages/react-native/ReactCommon/jsi/jsi/JSIDynamic.h b/packages/react-native/ReactCommon/jsi/jsi/JSIDynamic.h index 110dd13999f437..a96cc281b0d65b 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/JSIDynamic.h +++ b/packages/react-native/ReactCommon/jsi/jsi/JSIDynamic.h @@ -19,7 +19,8 @@ facebook::jsi::Value valueFromDynamic( folly::dynamic dynamicFromValue( facebook::jsi::Runtime& runtime, - const facebook::jsi::Value& value); + const facebook::jsi::Value& value, + std::function filterObjectKeys = nullptr); } // namespace jsi } // namespace facebook diff --git a/packages/react-native/ReactCommon/jsi/jsi/decorator.h b/packages/react-native/ReactCommon/jsi/jsi/decorator.h index baece80fe71d0f..7bddd1fad80a52 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/decorator.h +++ b/packages/react-native/ReactCommon/jsi/jsi/decorator.h @@ -252,6 +252,10 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { plain_.setNativeState(o, state); } + void setExternalMemoryPressure(const Object& obj, size_t amt) override { + plain_.setExternalMemoryPressure(obj, amt); + } + Value getProperty(const Object& o, const PropNameID& name) override { return plain_.getProperty(o, name); }; diff --git a/packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h b/packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h index 4ce00adb883c59..f3955815e41f06 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h +++ b/packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h @@ -227,6 +227,11 @@ inline void Object::setNativeState( runtime.setNativeState(*this, state); } +inline void Object::setExternalMemoryPressure(Runtime& runtime, size_t amt) + const { + runtime.setExternalMemoryPressure(*this, amt); +} + inline Array Object::getPropertyNames(Runtime& runtime) const { return runtime.getPropertyNames(*this); } diff --git a/packages/react-native/ReactCommon/jsi/jsi/jsi.h b/packages/react-native/ReactCommon/jsi/jsi/jsi.h index e5112b753b69d1..962dae93609423 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/jsi.h +++ b/packages/react-native/ReactCommon/jsi/jsi/jsi.h @@ -387,6 +387,11 @@ class JSI_EXPORT Runtime { virtual bool instanceOf(const Object& o, const Function& f) = 0; + /// See Object::setExternalMemoryPressure. + virtual void setExternalMemoryPressure( + const jsi::Object& obj, + size_t amount) = 0; + // These exist so derived classes can access the private parts of // Value, Symbol, String, and Object, which are all friends of Runtime. template @@ -834,6 +839,16 @@ class JSI_EXPORT Object : public Pointer { /// works. I only need it in one place.) Array getPropertyNames(Runtime& runtime) const; + /// Inform the runtime that there is additional memory associated with a given + /// JavaScript object that is not visible to the GC. This can be used if an + /// object is known to retain some native memory, and may be used to guide + /// decisions about when to run garbage collection. + /// This method may be invoked multiple times on an object, and subsequent + /// calls will overwrite any previously set value. Once the object is garbage + /// collected, the associated external memory will be considered freed and may + /// no longer factor into GC decisions. + void setExternalMemoryPressure(Runtime& runtime, size_t amt) const; + protected: void setPropertyValue( Runtime& runtime, diff --git a/packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp b/packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp index e24284112beb89..abb008e164226f 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp +++ b/packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp @@ -1520,6 +1520,25 @@ TEST_P(JSITest, NativeStateSymbolOverrides) { 42); } +TEST_P(JSITest, UTF8ExceptionTest) { + // Test that a native exception containing UTF-8 characters is correctly + // passed through. + Function throwUtf8 = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "throwUtf8"), + 1, + [](Runtime& rt, const Value&, const Value* args, size_t) -> Value { + throw JSINativeException(args[0].asString(rt).utf8(rt)); + }); + std::string utf8 = "👍"; + try { + throwUtf8.call(rt, utf8); + FAIL(); + } catch (const JSError& e) { + EXPECT_NE(e.getMessage().find(utf8), std::string::npos); + } +} + INSTANTIATE_TEST_CASE_P( Runtimes, JSITest, diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTBlockGuard.h b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTBlockGuard.h deleted file mode 100644 index 0e34516bedaa14..00000000000000 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTBlockGuard.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * RCTBlockGuard is designed to be used with obj-c blocks to assist with manual deallocation of C++ resources - * tied to lifetime of a block. If C++ resources needs to be manually released at the end of block or when the block - * is deallocated, place the clean up code inside constructor and make sure the instance of the class is references in - * the block. - */ -@interface RCTBlockGuard : NSObject - -- (instancetype)initWithCleanup:(void (^)(void))cleanup; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTBlockGuard.mm b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTBlockGuard.mm deleted file mode 100644 index c88429c67a8c53..00000000000000 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTBlockGuard.mm +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#import "RCTBlockGuard.h" - -@implementation RCTBlockGuard { - void (^_cleanup)(void); -} - -- (instancetype)initWithCleanup:(void (^)(void))cleanup -{ - if (self = [super init]) { - _cleanup = cleanup; - } - - return self; -} - -- (void)dealloc -{ - _cleanup(); -} - -@end diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/CMakeLists.txt b/packages/react-native/ReactCommon/react/renderer/components/textinput/CMakeLists.txt index 39e2a428bb64e6..3f780470383581 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/CMakeLists.txt @@ -15,12 +15,12 @@ add_compile_options( -Wno-gnu-zero-variadic-macro-arguments -DLOG_TAG=\"Fabric\") -file(GLOB rrc_textinput_SRC CONFIGURE_DEPENDS androidtextinput/react/renderer/components/androidtextinput/*.cpp) +file(GLOB rrc_textinput_SRC CONFIGURE_DEPENDS platform/android/react/renderer/components/androidtextinput/*.cpp) add_library(rrc_textinput SHARED ${rrc_textinput_SRC}) target_include_directories(rrc_textinput PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/androidtextinput/ + ${CMAKE_CURRENT_SOURCE_DIR}/platform/android/ ) target_link_libraries(rrc_textinput diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputState.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputState.cpp deleted file mode 100644 index a78a839b419db7..00000000000000 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputState.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "TextInputState.h" - -namespace facebook::react { - -#ifdef ANDROID -TextInputState::TextInputState( - const TextInputState& /*previousState*/, - const folly::dynamic& /*data*/){}; - -/* - * Empty implementation for Android because it doesn't use this class. - */ -folly::dynamic TextInputState::getDynamic() const { - return {}; -}; - -/* - * Empty implementation for Android because it doesn't use this class. - */ -MapBuffer TextInputState::getMapBuffer() const { - return MapBufferBuilder::EMPTY(); -}; -#endif - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h similarity index 81% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h index 04d19a11bfbdb6..6ee6c1e73c192c 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h @@ -13,7 +13,6 @@ #include #include -#include #include @@ -40,7 +39,7 @@ class AndroidTextInputComponentDescriptor final const ShadowNodeFamily::Shared& family) const override { int surfaceId = family->getSurfaceId(); - yoga::Style::Edges theme; + ThemePadding theme; // TODO: figure out RTL/start/end/left/right stuff here if (surfaceIdToThemePaddingMap_.find(surfaceId) != surfaceIdToThemePaddingMap_.end()) { @@ -59,11 +58,10 @@ class AndroidTextInputComponentDescriptor final fabricUIManager, surfaceId, defaultTextInputPaddingArray)) { jfloat* defaultTextInputPadding = env->GetFloatArrayElements(defaultTextInputPaddingArray, 0); - theme[YGEdgeStart] = (YGValue){defaultTextInputPadding[0], YGUnitPoint}; - theme[YGEdgeEnd] = (YGValue){defaultTextInputPadding[1], YGUnitPoint}; - theme[YGEdgeTop] = (YGValue){defaultTextInputPadding[2], YGUnitPoint}; - theme[YGEdgeBottom] = - (YGValue){defaultTextInputPadding[3], YGUnitPoint}; + theme.start = defaultTextInputPadding[0]; + theme.end = defaultTextInputPadding[1]; + theme.top = defaultTextInputPadding[2]; + theme.bottom = defaultTextInputPadding[3]; surfaceIdToThemePaddingMap_.emplace(std::make_pair(surfaceId, theme)); env->ReleaseFloatArrayElements( defaultTextInputPaddingArray, defaultTextInputPadding, JNI_ABORT); @@ -73,14 +71,7 @@ class AndroidTextInputComponentDescriptor final return std::make_shared( std::make_shared(AndroidTextInputState( - 0, - {}, - {}, - {}, - ((YGValue)theme[YGEdgeStart]).value, - ((YGValue)theme[YGEdgeEnd]).value, - ((YGValue)theme[YGEdgeTop]).value, - ((YGValue)theme[YGEdgeBottom]).value)), + 0, {}, {}, {}, theme.start, theme.end, theme.top, theme.bottom)), family); } @@ -99,7 +90,7 @@ class AndroidTextInputComponentDescriptor final int surfaceId = textInputShadowNode.getSurfaceId(); if (surfaceIdToThemePaddingMap_.find(surfaceId) != surfaceIdToThemePaddingMap_.end()) { - yoga::Style::Edges theme = surfaceIdToThemePaddingMap_[surfaceId]; + const auto& theme = surfaceIdToThemePaddingMap_[surfaceId]; auto& textInputProps = textInputShadowNode.getConcreteProps(); @@ -108,29 +99,29 @@ class AndroidTextInputComponentDescriptor final // TODO: T62959168 account for RTL and paddingLeft when setting default // paddingStart, and vice-versa with paddingRight/paddingEnd. // For now this assumes no RTL. - yoga::Style::Edges result = textInputProps.yogaStyle.padding(); + auto& style = const_cast(textInputProps.yogaStyle); bool changedPadding = false; if (!textInputProps.hasPadding && !textInputProps.hasPaddingStart && !textInputProps.hasPaddingLeft && !textInputProps.hasPaddingHorizontal) { changedPadding = true; - result[YGEdgeStart] = theme[YGEdgeStart]; + style.setPadding(yoga::Edge::Start, yoga::value::points(theme.start)); } if (!textInputProps.hasPadding && !textInputProps.hasPaddingEnd && !textInputProps.hasPaddingRight && !textInputProps.hasPaddingHorizontal) { changedPadding = true; - result[YGEdgeEnd] = theme[YGEdgeEnd]; + style.setPadding(yoga::Edge::End, yoga::value::points(theme.end)); } if (!textInputProps.hasPadding && !textInputProps.hasPaddingTop && !textInputProps.hasPaddingVertical) { changedPadding = true; - result[YGEdgeTop] = theme[YGEdgeTop]; + style.setPadding(yoga::Edge::Top, yoga::value::points(theme.top)); } if (!textInputProps.hasPadding && !textInputProps.hasPaddingBottom && !textInputProps.hasPaddingVertical) { changedPadding = true; - result[YGEdgeBottom] = theme[YGEdgeBottom]; + style.setPadding(yoga::Edge::Bottom, yoga::value::points(theme.bottom)); } // If the TextInput initially does not have paddingLeft or paddingStart, a @@ -141,21 +132,18 @@ class AndroidTextInputComponentDescriptor final if ((textInputProps.hasPadding || textInputProps.hasPaddingLeft || textInputProps.hasPaddingHorizontal) && !textInputProps.hasPaddingStart) { - result[YGEdgeStart] = YGValueUndefined; + style.setPadding(yoga::Edge::Start, yoga::value::undefined()); } if ((textInputProps.hasPadding || textInputProps.hasPaddingRight || textInputProps.hasPaddingHorizontal) && !textInputProps.hasPaddingEnd) { - result[YGEdgeEnd] = YGValueUndefined; + style.setPadding(yoga::Edge::End, yoga::value::undefined()); } // Note that this is expensive: on every adopt, we need to set the Yoga // props again, which normally only happens during prop parsing. Every // commit, state update, etc, will incur this cost. if (changedPadding) { - // Set new props on node - const_cast(textInputProps).yogaStyle.padding() = - result; // Communicate new props to Yoga part of the node textInputShadowNode.updateYogaProps(); } @@ -168,13 +156,19 @@ class AndroidTextInputComponentDescriptor final } private: + struct ThemePadding { + float start{}; + float end{}; + float top{}; + float bottom{}; + }; + // TODO T68526882: Unify with Binding::UIManagerJavaDescriptor constexpr static auto UIManagerJavaDescriptor = "com/facebook/react/fabric/FabricUIManager"; SharedTextLayoutManager textLayoutManager_; - mutable std::unordered_map - surfaceIdToThemePaddingMap_; + mutable std::unordered_map surfaceIdToThemePaddingMap_; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputEventEmitter.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputEventEmitter.h similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputEventEmitter.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputEventEmitter.h diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp similarity index 95% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp index 116284f1c6bcaa..ea0fb6a1674e3d 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp @@ -13,13 +13,9 @@ namespace facebook::react { -static bool hasValue( - const RawProps& rawProps, - bool defaultValue, - const char* name, - const char* prefix, - const char* suffix) { - auto rawValue = rawProps.at(name, prefix, suffix); +static bool +hasValue(const RawProps& rawProps, bool defaultValue, const char* name) { + auto rawValue = rawProps.at(name, nullptr, nullptr); // No change to prop - use default if (rawValue == nullptr) { @@ -134,6 +130,10 @@ AndroidTextInputProps::AndroidTextInputProps( "selectionColor", sourceProps.selectionColor, {})), + selectionHandleColor(CoreFeatures::enablePropIteratorSetter? sourceProps.selectionHandleColor : convertRawProp(context, rawProps, + "selectionHandleColor", + sourceProps.selectionHandleColor, + {})), value(CoreFeatures::enablePropIteratorSetter? sourceProps.value : convertRawProp(context, rawProps, "value", sourceProps.value, {})), defaultValue(CoreFeatures::enablePropIteratorSetter? sourceProps.defaultValue : convertRawProp(context, rawProps, "defaultValue", @@ -213,47 +213,35 @@ AndroidTextInputProps::AndroidTextInputProps( convertRawProp(context, rawProps, sourceProps.paragraphAttributes, {})), // See AndroidTextInputComponentDescriptor for usage // TODO T63008435: can these, and this feature, be removed entirely? - hasPadding(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPadding : hasValue(rawProps, sourceProps.hasPadding, "", "padding", "")), + hasPadding(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPadding : hasValue(rawProps, sourceProps.hasPadding, "padding")), hasPaddingHorizontal(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPaddingHorizontal : hasValue( rawProps, sourceProps.hasPaddingHorizontal, - "Horizontal", - "padding", - "")), + "paddingHorizontal")), hasPaddingVertical(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPaddingVertical : hasValue( rawProps, sourceProps.hasPaddingVertical, - "Vertical", - "padding", - "")), + "paddingVertical")), hasPaddingLeft(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPaddingLeft : hasValue( rawProps, sourceProps.hasPaddingLeft, - "Left", - "padding", - "")), + "paddingLeft")), hasPaddingTop(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPaddingTop : - hasValue(rawProps, sourceProps.hasPaddingTop, "Top", "padding", "")), + hasValue(rawProps, sourceProps.hasPaddingTop, "paddingTop")), hasPaddingRight(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPaddingRight : hasValue( rawProps, sourceProps.hasPaddingRight, - "Right", - "padding", - "")), + "paddingRight")), hasPaddingBottom(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPaddingBottom : hasValue( rawProps, sourceProps.hasPaddingBottom, - "Bottom", - "padding", - "")), + "paddingBottom")), hasPaddingStart(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPaddingStart : hasValue( rawProps, sourceProps.hasPaddingStart, - "Start", - "padding", - "")), + "paddingStart")), hasPaddingEnd(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPaddingEnd : - hasValue(rawProps, sourceProps.hasPaddingEnd, "End", "padding", "")) { + hasValue(rawProps, sourceProps.hasPaddingEnd, "paddingEnd")) { } void AndroidTextInputProps::setProp( @@ -347,6 +335,7 @@ void AndroidTextInputProps::setProp( RAW_SET_PROP_SWITCH_CASE_BASIC(placeholderTextColor); RAW_SET_PROP_SWITCH_CASE_BASIC(secureTextEntry); RAW_SET_PROP_SWITCH_CASE_BASIC(selectionColor); + RAW_SET_PROP_SWITCH_CASE_BASIC(selectionHandleColor); RAW_SET_PROP_SWITCH_CASE_BASIC(defaultValue); RAW_SET_PROP_SWITCH_CASE_BASIC(selectTextOnFocus); RAW_SET_PROP_SWITCH_CASE_BASIC(submitBehavior); @@ -446,6 +435,7 @@ folly::dynamic AndroidTextInputProps::getDynamic() const { props["placeholderTextColor"] = toAndroidRepr(placeholderTextColor); props["secureTextEntry"] = secureTextEntry; props["selectionColor"] = toAndroidRepr(selectionColor); + props["selectionHandleColor"] = toAndroidRepr(selectionHandleColor); props["value"] = value; props["defaultValue"] = defaultValue; props["selectTextOnFocus"] = selectTextOnFocus; diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.h similarity index 99% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.h index 43cbb6859047f3..82fb75ea1028e4 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.h @@ -50,7 +50,6 @@ static inline std::string toString( return "[Object AndroidTextInputTextShadowOffsetStruct]"; } -#ifdef ANDROID inline folly::dynamic toDynamic( const AndroidTextInputTextShadowOffsetStruct& value) { folly::dynamic dynamicValue = folly::dynamic::object(); @@ -58,7 +57,6 @@ inline folly::dynamic toDynamic( dynamicValue["height"] = value.height; return dynamicValue; } -#endif class AndroidTextInputProps final : public ViewProps, public BaseTextProps { public: @@ -102,6 +100,7 @@ class AndroidTextInputProps final : public ViewProps, public BaseTextProps { SharedColor placeholderTextColor{}; bool secureTextEntry{false}; SharedColor selectionColor{}; + SharedColor selectionHandleColor{}; std::string value{}; std::string defaultValue{}; bool selectTextOnFocus{false}; diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputState.cpp similarity index 98% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.cpp rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputState.cpp index 83607848e4d342..ab5516d796e87a 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputState.cpp @@ -9,11 +9,8 @@ #include #include - -#ifdef ANDROID #include #include -#endif #include @@ -68,7 +65,6 @@ AndroidTextInputState::AndroidTextInputState( previousState.defaultThemePaddingBottom) .getDouble()){}; -#ifdef ANDROID folly::dynamic AndroidTextInputState::getDynamic() const { // Java doesn't need all fields, so we don't pass them all along. folly::dynamic newState = folly::dynamic::object(); @@ -104,6 +100,4 @@ MapBuffer AndroidTextInputState::getMapBuffer() const { return builder.build(); } -#endif - } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputState.h similarity index 99% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputState.h index 1cf73cca7c74c8..b7e4532738ee99 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputState.h @@ -7,15 +7,12 @@ #pragma once +#include #include #include -#include - -#ifdef ANDROID -#include #include #include -#endif +#include namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputComponentDescriptor.h similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputComponentDescriptor.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputComponentDescriptor.h diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.cpp rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.h similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.h diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputProps.cpp similarity index 95% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputProps.cpp rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputProps.cpp index 3e4b712e91d06c..a825971ddbe8c8 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputProps.cpp @@ -62,6 +62,12 @@ TextInputProps::TextInputProps( "selectionColor", sourceProps.selectionColor, {})), + selectionHandleColor(convertRawProp( + context, + rawProps, + "selectionHandleColor", + sourceProps.selectionHandleColor, + {})), underlineColorAndroid(convertRawProp( context, rawProps, diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputProps.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputProps.h similarity index 98% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputProps.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputProps.h index 203f762ede10ab..e3db155099c78e 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputProps.h @@ -53,6 +53,7 @@ class TextInputProps final : public ViewProps, public BaseTextProps { */ const SharedColor cursorColor{}; const SharedColor selectionColor{}; + const SharedColor selectionHandleColor{}; // TODO: Rename to `tintColor` and make universal. const SharedColor underlineColorAndroid{}; diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputShadowNode.cpp similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputShadowNode.cpp rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputShadowNode.cpp diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputShadowNode.h similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputShadowNode.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputShadowNode.h diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputState.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputState.cpp new file mode 100644 index 00000000000000..abe682f52e19a1 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputState.cpp @@ -0,0 +1,10 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TextInputState.h" + +namespace facebook::react {} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputState.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputState.h similarity index 81% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputState.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputState.h index 3a11436d43608d..fe7dab58255258 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputState.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputState.h @@ -11,12 +11,6 @@ #include #include -#ifdef ANDROID -#include -#include -#include -#endif - namespace facebook::react { /* @@ -54,16 +48,6 @@ class TextInputState final { std::shared_ptr layoutManager; size_t mostRecentEventCount{0}; - -#ifdef ANDROID - TextInputState( - const TextInputState& previousState, - const folly::dynamic& data); - - folly::dynamic getDynamic() const; - - MapBuffer getMapBuffer() const; -#endif }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/conversions.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/conversions.h similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/conversions.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/conversions.h diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/primitives.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/primitives.h similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/primitives.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/primitives.h diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/propsConversions.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/propsConversions.h similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/propsConversions.h rename to packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/propsConversions.h diff --git a/packages/react-native/ReactCommon/react/renderer/components/unimplementedview/UnimplementedViewComponentDescriptor.cpp b/packages/react-native/ReactCommon/react/renderer/components/unimplementedview/UnimplementedViewComponentDescriptor.cpp index 1fd2a48271aa89..7b42990f7c414b 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/unimplementedview/UnimplementedViewComponentDescriptor.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/unimplementedview/UnimplementedViewComponentDescriptor.cpp @@ -21,19 +21,19 @@ ComponentName UnimplementedViewComponentDescriptor::getComponentName() const { Props::Shared UnimplementedViewComponentDescriptor::cloneProps( const PropsParserContext& context, const Props::Shared& props, - const RawProps& rawProps) const { + RawProps rawProps) const { auto clonedProps = ConcreteComponentDescriptor::cloneProps( - context, props, rawProps); + context, props, std::move(rawProps)); // We have to clone `Props` object one more time to make sure that we have // an unshared (and non-`const`) copy of it which we can mutate. RawProps emptyRawProps{}; - emptyRawProps.parse(rawPropsParser_, context); + emptyRawProps.parse(rawPropsParser_); auto unimplementedViewProps = std::make_shared( context, static_cast(*clonedProps), - emptyRawProps); + std::move(emptyRawProps)); unimplementedViewProps->setComponentName(getComponentName()); return unimplementedViewProps; diff --git a/packages/react-native/ReactCommon/react/renderer/components/unimplementedview/UnimplementedViewComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/components/unimplementedview/UnimplementedViewComponentDescriptor.h index 6240fae281d820..e73046568de792 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/unimplementedview/UnimplementedViewComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/components/unimplementedview/UnimplementedViewComponentDescriptor.h @@ -35,7 +35,7 @@ class UnimplementedViewComponentDescriptor final Props::Shared cloneProps( const PropsParserContext& context, const Props::Shared& props, - const RawProps& rawProps) const override; + RawProps rawProps) const override; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp index 58bb38b20385c1..3d55f25c38cb9c 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp @@ -358,20 +358,24 @@ BorderMetrics BaseViewProps::resolveBorderMetrics( bool{layoutMetrics.layoutDirection == LayoutDirection::RightToLeft}; auto borderWidths = CascadedBorderWidths{ - /* .left = */ optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeLeft]), - /* .top = */ optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeTop]), + /* .left = */ optionalFloatFromYogaValue( + yogaStyle.border(yoga::Edge::Left)), + /* .top = */ + optionalFloatFromYogaValue(yogaStyle.border(yoga::Edge::Top)), /* .right = */ - optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeRight]), + optionalFloatFromYogaValue(yogaStyle.border(yoga::Edge::Right)), /* .bottom = */ - optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeBottom]), + optionalFloatFromYogaValue(yogaStyle.border(yoga::Edge::Bottom)), /* .start = */ - optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeStart]), - /* .end = */ optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeEnd]), + optionalFloatFromYogaValue(yogaStyle.border(yoga::Edge::Start)), + /* .end = */ + optionalFloatFromYogaValue(yogaStyle.border(yoga::Edge::End)), /* .horizontal = */ - optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeHorizontal]), + optionalFloatFromYogaValue(yogaStyle.border(yoga::Edge::Horizontal)), /* .vertical = */ - optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeVertical]), - /* .all = */ optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeAll]), + optionalFloatFromYogaValue(yogaStyle.border(yoga::Edge::Vertical)), + /* .all = */ + optionalFloatFromYogaValue(yogaStyle.border(yoga::Edge::All)), }; return { diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.cpp index 42575ec6085f35..fe11e92e1a5771 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.cpp @@ -39,6 +39,15 @@ ViewShadowNode::ViewShadowNode( void ViewShadowNode::initialize() noexcept { auto& viewProps = static_cast(*props_); + auto hasBorder = [&]() { + for (auto edge : yoga::ordinals()) { + if (viewProps.yogaStyle.border(edge).isDefined()) { + return true; + } + } + return false; + }; + bool formsStackingContext = !viewProps.collapsable || viewProps.pointerEvents == PointerEventsMode::None || !viewProps.nativeId.empty() || viewProps.accessible || @@ -55,8 +64,7 @@ void ViewShadowNode::initialize() noexcept { HostPlatformViewTraitsInitializer::formsStackingContext(viewProps); bool formsView = formsStackingContext || - isColorMeaningful(viewProps.backgroundColor) || - !(viewProps.yogaStyle.border() == yoga::Style::Edges{}) || + isColorMeaningful(viewProps.backgroundColor) || hasBorder() || !viewProps.testId.empty() || HostPlatformViewTraitsInitializer::formsView(viewProps); diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp index 3bfa3a97f2394f..7757bd6695dbf6 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp @@ -391,64 +391,55 @@ void YogaLayoutableShadowNode::updateYogaProps() { yoga::Style result{baseStyle}; // Aliases with precedence - if (!props.inset.isUndefined()) { - result.position()[YGEdgeAll] = props.inset; + if (props.insetInlineEnd.isDefined()) { + result.setPosition(yoga::Edge::End, props.insetInlineEnd); } - if (!props.insetBlock.isUndefined()) { - result.position()[YGEdgeVertical] = props.insetBlock; + if (props.insetInlineStart.isDefined()) { + result.setPosition(yoga::Edge::Start, props.insetInlineStart); } - if (!props.insetInline.isUndefined()) { - result.position()[YGEdgeHorizontal] = props.insetInline; + if (props.marginInline.isDefined()) { + result.setMargin(yoga::Edge::Horizontal, props.marginInline); } - if (!props.insetInlineEnd.isUndefined()) { - result.position()[YGEdgeEnd] = props.insetInlineEnd; + if (props.marginInlineStart.isDefined()) { + result.setMargin(yoga::Edge::Start, props.marginInlineStart); } - if (!props.insetInlineStart.isUndefined()) { - result.position()[YGEdgeStart] = props.insetInlineStart; + if (props.marginInlineEnd.isDefined()) { + result.setMargin(yoga::Edge::End, props.marginInlineEnd); } - if (!props.marginInline.isUndefined()) { - result.margin()[YGEdgeHorizontal] = props.marginInline; + if (props.marginBlock.isDefined()) { + result.setMargin(yoga::Edge::Vertical, props.marginBlock); } - if (!props.marginInlineStart.isUndefined()) { - result.margin()[YGEdgeStart] = props.marginInlineStart; + if (props.paddingInline.isDefined()) { + result.setPadding(yoga::Edge::Horizontal, props.paddingInline); } - if (!props.marginInlineEnd.isUndefined()) { - result.margin()[YGEdgeEnd] = props.marginInlineEnd; + if (props.paddingInlineStart.isDefined()) { + result.setPadding(yoga::Edge::Start, props.paddingInlineStart); } - if (!props.marginBlock.isUndefined()) { - result.margin()[YGEdgeVertical] = props.marginBlock; + if (props.paddingInlineEnd.isDefined()) { + result.setPadding(yoga::Edge::End, props.paddingInlineEnd); } - if (!props.paddingInline.isUndefined()) { - result.padding()[YGEdgeHorizontal] = props.paddingInline; - } - if (!props.paddingInlineStart.isUndefined()) { - result.padding()[YGEdgeStart] = props.paddingInlineStart; - } - if (!props.paddingInlineEnd.isUndefined()) { - result.padding()[YGEdgeEnd] = props.paddingInlineEnd; - } - if (!props.paddingBlock.isUndefined()) { - result.padding()[YGEdgeVertical] = props.paddingBlock; + if (props.paddingBlock.isDefined()) { + result.setPadding(yoga::Edge::Vertical, props.paddingBlock); } // Aliases without precedence - if (CompactValue(result.position()[YGEdgeBottom]).isUndefined()) { - result.position()[YGEdgeBottom] = props.insetBlockEnd; + if (result.position(yoga::Edge::Bottom).isUndefined()) { + result.setPosition(yoga::Edge::Bottom, props.insetBlockEnd); } - if (CompactValue(result.position()[YGEdgeTop]).isUndefined()) { - result.position()[YGEdgeTop] = props.insetBlockStart; + if (result.position(yoga::Edge::Top).isUndefined()) { + result.setPosition(yoga::Edge::Top, props.insetBlockStart); } - if (CompactValue(result.margin()[YGEdgeTop]).isUndefined()) { - result.margin()[YGEdgeTop] = props.marginBlockStart; + if (result.margin(yoga::Edge::Top).isUndefined()) { + result.setMargin(yoga::Edge::Top, props.marginBlockStart); } - if (CompactValue(result.margin()[YGEdgeBottom]).isUndefined()) { - result.margin()[YGEdgeBottom] = props.marginBlockEnd; + if (result.margin(yoga::Edge::Bottom).isUndefined()) { + result.setMargin(yoga::Edge::Bottom, props.marginBlockEnd); } - if (CompactValue(result.padding()[YGEdgeTop]).isUndefined()) { - result.padding()[YGEdgeTop] = props.paddingBlockStart; + if (result.padding(yoga::Edge::Top).isUndefined()) { + result.setPadding(yoga::Edge::Top, props.paddingBlockStart); } - if (CompactValue(result.padding()[YGEdgeBottom]).isUndefined()) { - result.padding()[YGEdgeBottom] = props.paddingBlockEnd; + if (result.padding(yoga::Edge::Bottom).isUndefined()) { + result.setPadding(yoga::Edge::Bottom, props.paddingBlockEnd); } return result; @@ -479,8 +470,7 @@ void YogaLayoutableShadowNode::configureYogaTree( for (size_t i = 0; i < yogaLayoutableChildren_.size(); i++) { const auto& child = *yogaLayoutableChildren_[i]; auto childLayoutMetrics = child.getLayoutMetrics(); - auto childErrata = - YGConfigGetErrata(const_cast(&child.yogaConfig_)); + auto childErrata = YGConfigGetErrata(&child.yogaConfig_); if (child.yogaTreeHasBeenConfigured_ && childLayoutMetrics.pointScaleFactor == pointScaleFactor && @@ -538,12 +528,8 @@ void YogaLayoutableShadowNode::setSize(Size size) const { ensureUnsealed(); auto style = yogaNode_.getStyle(); - style.setDimension( - yoga::Dimension::Width, - yoga::CompactValue::ofMaybe(size.width)); - style.setDimension( - yoga::Dimension::Height, - yoga::CompactValue::ofMaybe(size.height)); + style.setDimension(yoga::Dimension::Width, yoga::value::points(size.width)); + style.setDimension(yoga::Dimension::Height, yoga::value::points(size.height)); yogaNode_.setStyle(style); yogaNode_.setDirty(true); } @@ -553,23 +539,19 @@ void YogaLayoutableShadowNode::setPadding(RectangleEdges padding) const { auto style = yogaNode_.getStyle(); - auto leftPadding = yoga::CompactValue::ofMaybe(padding.left); - auto topPadding = yoga::CompactValue::ofMaybe(padding.top); - auto rightPadding = yoga::CompactValue::ofMaybe(padding.right); - auto bottomPadding = yoga::CompactValue::ofMaybe(padding.bottom); - - if (leftPadding != style.padding()[YGEdgeLeft] || - topPadding != style.padding()[YGEdgeTop] || - rightPadding != style.padding()[YGEdgeRight] || - bottomPadding != style.padding()[YGEdgeBottom]) { - style.padding()[YGEdgeTop] = - yoga::CompactValue::ofMaybe(padding.top); - style.padding()[YGEdgeLeft] = - yoga::CompactValue::ofMaybe(padding.left); - style.padding()[YGEdgeRight] = - yoga::CompactValue::ofMaybe(padding.right); - style.padding()[YGEdgeBottom] = - yoga::CompactValue::ofMaybe(padding.bottom); + auto leftPadding = yoga::value::points(padding.left); + auto topPadding = yoga::value::points(padding.top); + auto rightPadding = yoga::value::points(padding.right); + auto bottomPadding = yoga::value::points(padding.bottom); + + if (leftPadding != style.padding(yoga::Edge::Left) || + topPadding != style.padding(yoga::Edge::Top) || + rightPadding != style.padding(yoga::Edge::Right) || + bottomPadding != style.padding(yoga::Edge::Bottom)) { + style.setPadding(yoga::Edge::Top, yoga::value::points(padding.top)); + style.setPadding(yoga::Edge::Left, yoga::value::points(padding.left)); + style.setPadding(yoga::Edge::Right, yoga::value::points(padding.right)); + style.setPadding(yoga::Edge::Bottom, yoga::value::points(padding.bottom)); yogaNode_.setStyle(style); yogaNode_.setDirty(true); } @@ -580,7 +562,7 @@ void YogaLayoutableShadowNode::setPositionType( ensureUnsealed(); auto style = yogaNode_.getStyle(); - style.positionType() = yoga::scopedEnum(positionType); + style.setPositionType(yoga::scopedEnum(positionType)); yogaNode_.setStyle(style); yogaNode_.setDirty(true); } @@ -622,13 +604,11 @@ void YogaLayoutableShadowNode::layoutTree( react_native_assert(!std::isinf(minimumSize.width)); react_native_assert(!std::isinf(minimumSize.height)); - // Internally Yoga uses three different measurement modes controlling layout - // constraints: `Undefined`, `Exactly`, and `AtMost`. These modes are an - // implementation detail and are not defined in `CSS Flexible Box Layout - // Module`. Yoga C++ API (and `YGNodeCalculateLayout` function particularly) - // does not allow to specify the measure modes explicitly. Instead, it infers - // these from styles associated with the root node. - // To pass the actual layout constraints to Yoga we represent them as + // Yoga C++ API (and `YGNodeCalculateLayout` function particularly) + // does not allow to specify sizing modes (see + // https://www.w3.org/TR/css-sizing-3/#auto-box-sizes) explicitly. Instead, it + // infers these from styles associated with the root node. To pass the actual + // layout constraints to Yoga we represent them as // `(min/max)(Height/Width)` style properties. Also, we pass `ownerWidth` & // `ownerHeight` to allow proper calculation of relative (e.g. specified in // percents) style values. @@ -639,20 +619,16 @@ void YogaLayoutableShadowNode::layoutTree( auto ownerHeight = yogaFloatFromFloat(maximumSize.height); yogaStyle.setMaxDimension( - yoga::Dimension::Width, - yoga::CompactValue::ofMaybe(maximumSize.width)); + yoga::Dimension::Width, yoga::value::points(maximumSize.width)); yogaStyle.setMaxDimension( - yoga::Dimension::Height, - yoga::CompactValue::ofMaybe(maximumSize.height)); + yoga::Dimension::Height, yoga::value::points(maximumSize.height)); yogaStyle.setMinDimension( - yoga::Dimension::Width, - yoga::CompactValue::ofMaybe(minimumSize.width)); + yoga::Dimension::Width, yoga::value::points(minimumSize.width)); yogaStyle.setMinDimension( - yoga::Dimension::Height, - yoga::CompactValue::ofMaybe(minimumSize.height)); + yoga::Dimension::Height, yoga::value::points(minimumSize.height)); auto direction = yogaDirectionFromLayoutDirection(layoutConstraints.layoutDirection); @@ -892,40 +868,39 @@ void YogaLayoutableShadowNode::swapLeftAndRightInYogaStyleProps( const YogaLayoutableShadowNode& shadowNode) { auto yogaStyle = shadowNode.yogaNode_.getStyle(); - const yoga::Style::Edges& position = yogaStyle.position(); - const yoga::Style::Edges& padding = yogaStyle.padding(); - const yoga::Style::Edges& margin = yogaStyle.margin(); - // Swap Yoga node values, position, padding and margin. - if (yogaStyle.position()[YGEdgeLeft] != YGValueUndefined) { - yogaStyle.position()[YGEdgeStart] = position[YGEdgeLeft]; - yogaStyle.position()[YGEdgeLeft] = YGValueUndefined; + if (yogaStyle.position(yoga::Edge::Left).isDefined()) { + yogaStyle.setPosition( + yoga::Edge::Start, yogaStyle.position(yoga::Edge::Left)); + yogaStyle.setPosition(yoga::Edge::Left, yoga::value::undefined()); } - if (yogaStyle.position()[YGEdgeRight] != YGValueUndefined) { - yogaStyle.position()[YGEdgeEnd] = position[YGEdgeRight]; - yogaStyle.position()[YGEdgeRight] = YGValueUndefined; + if (yogaStyle.position(yoga::Edge::Right).isDefined()) { + yogaStyle.setPosition( + yoga::Edge::End, yogaStyle.position(yoga::Edge::Right)); + yogaStyle.setPosition(yoga::Edge::Right, yoga::value::undefined()); } - if (yogaStyle.padding()[YGEdgeLeft] != YGValueUndefined) { - yogaStyle.padding()[YGEdgeStart] = padding[YGEdgeLeft]; - yogaStyle.padding()[YGEdgeLeft] = YGValueUndefined; + if (yogaStyle.padding(yoga::Edge::Left).isDefined()) { + yogaStyle.setPadding( + yoga::Edge::Start, yogaStyle.padding(yoga::Edge::Left)); + yogaStyle.setPadding(yoga::Edge::Left, yoga::value::undefined()); } - if (yogaStyle.padding()[YGEdgeRight] != YGValueUndefined) { - yogaStyle.padding()[YGEdgeEnd] = padding[YGEdgeRight]; - yogaStyle.padding()[YGEdgeRight] = YGValueUndefined; + if (yogaStyle.padding(yoga::Edge::Right).isDefined()) { + yogaStyle.setPadding(yoga::Edge::End, yogaStyle.padding(yoga::Edge::Right)); + yogaStyle.setPadding(yoga::Edge::Right, yoga::value::undefined()); } - if (yogaStyle.margin()[YGEdgeLeft] != YGValueUndefined) { - yogaStyle.margin()[YGEdgeStart] = margin[YGEdgeLeft]; - yogaStyle.margin()[YGEdgeLeft] = YGValueUndefined; + if (yogaStyle.margin(yoga::Edge::Left).isDefined()) { + yogaStyle.setMargin(yoga::Edge::Start, yogaStyle.margin(yoga::Edge::Left)); + yogaStyle.setMargin(yoga::Edge::Left, yoga::value::undefined()); } - if (yogaStyle.margin()[YGEdgeRight] != YGValueUndefined) { - yogaStyle.margin()[YGEdgeEnd] = margin[YGEdgeRight]; - yogaStyle.margin()[YGEdgeRight] = YGValueUndefined; + if (yogaStyle.margin(yoga::Edge::Right).isDefined()) { + yogaStyle.setMargin(yoga::Edge::End, yogaStyle.margin(yoga::Edge::Right)); + yogaStyle.setMargin(yoga::Edge::Right, yoga::value::undefined()); } shadowNode.yogaNode_.setStyle(yogaStyle); @@ -978,16 +953,16 @@ void YogaLayoutableShadowNode::swapLeftAndRightInViewProps( props.borderStyles.right.reset(); } - const yoga::Style::Edges& border = props.yogaStyle.border(); - - if (props.yogaStyle.border()[YGEdgeLeft] != YGValueUndefined) { - props.yogaStyle.border()[YGEdgeStart] = border[YGEdgeLeft]; - props.yogaStyle.border()[YGEdgeLeft] = YGValueUndefined; + if (props.yogaStyle.border(yoga::Edge::Left).isDefined()) { + props.yogaStyle.setBorder( + yoga::Edge::Start, props.yogaStyle.border(yoga::Edge::Left)); + props.yogaStyle.setBorder(yoga::Edge::Left, yoga::value::undefined()); } - if (props.yogaStyle.border()[YGEdgeRight] != YGValueUndefined) { - props.yogaStyle.border()[YGEdgeEnd] = border[YGEdgeRight]; - props.yogaStyle.border()[YGEdgeRight] = YGValueUndefined; + if (props.yogaStyle.border(yoga::Edge::Right).isDefined()) { + props.yogaStyle.setBorder( + yoga::Edge::End, props.yogaStyle.border(yoga::Edge::Right)); + props.yogaStyle.setBorder(yoga::Edge::Right, yoga::value::undefined()); } } diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h index 0d31fb56eae31c..f4a9ba794362a8 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h @@ -22,8 +22,6 @@ namespace facebook::react { class YogaLayoutableShadowNode : public LayoutableShadowNode { - using CompactValue = facebook::yoga::CompactValue; - public: using Shared = std::shared_ptr; using ListOfShared = std::vector; diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp index 607ed67c9d8be4..996b976bae4294 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp @@ -19,137 +19,34 @@ namespace facebook::react { -namespace { -inline RawProps filterYogaProps(const RawProps& rawProps) { - const static std::unordered_set yogaStylePropNames = { - {"direction", - "flexDirection", - "justifyContent", - "alignContent", - "alignItems", - "alignSelf", - "position", - "flexWrap", - "display", - "flex", - "flexGrow", - "flexShrink", - "flexBasis", - "margin", - "padding", - "rowGap", - "columnGap", - "gap", - // TODO: T163711275 also filter out width/height when SVG no longer read - // them from RawProps - "minWidth", - "maxWidth", - "minHeight", - "maxHeight", - "aspectRatio", - - // edges - "left", - "right", - "top", - "bottom", - "start", - "end", - - // variants of inset - "inset", - "insetStart", - "insetEnd", - "insetInline", - "insetInlineStart", - "insetInlineEnd", - "insetBlock", - "insetBlockEnd", - "insetBlockStart", - "insetVertical", - "insetHorizontal", - "insetTop", - "insetBottom", - "insetLeft", - "insetRight", - - // variants of margin - "marginStart", - "marginEnd", - "marginInline", - "marginInlineStart", - "marginInlineEnd", - "marginBlock", - "marginBlockStart", - "marginBlockEnd", - "marginVertical", - "marginHorizontal", - "marginTop", - "marginBottom", - "marginLeft", - "marginRight", - - // variants of padding - "paddingStart", - "paddingEnd", - "paddingInline", - "paddingInlineStart", - "paddingInlineEnd", - "paddingBlock", - "paddingBlockStart", - "paddingBlockEnd", - "paddingVertical", - "paddingHorizontal", - "paddingTop", - "paddingBottom", - "paddingLeft", - "paddingRight"}}; - - auto filteredRawProps = (folly::dynamic)rawProps; - - auto it = filteredRawProps.items().begin(); - while (it != filteredRawProps.items().end()) { - auto key = it->first.asString(); - if (yogaStylePropNames.find(key) != yogaStylePropNames.end()) { - it = filteredRawProps.erase(it); - } else { - ++it; - } - } - - return RawProps(std::move(filteredRawProps)); -} -} // namespace - YogaStylableProps::YogaStylableProps( const PropsParserContext& context, const YogaStylableProps& sourceProps, const RawProps& rawProps) : Props() { - if (CoreFeatures::excludeYogaFromRawProps) { - const auto filteredRawProps = filterYogaProps(rawProps); - initialize(context, sourceProps, filteredRawProps); - - yogaStyle = CoreFeatures::enablePropIteratorSetter - ? sourceProps.yogaStyle - : convertRawProp(context, filteredRawProps, sourceProps.yogaStyle); + initialize(context, sourceProps, rawProps); - if (!CoreFeatures::enablePropIteratorSetter) { - convertRawPropAliases(context, sourceProps, filteredRawProps); - } - } else { - initialize(context, sourceProps, rawProps); + yogaStyle = CoreFeatures::enablePropIteratorSetter + ? sourceProps.yogaStyle + : convertRawProp(context, rawProps, sourceProps.yogaStyle); - yogaStyle = CoreFeatures::enablePropIteratorSetter - ? sourceProps.yogaStyle - : convertRawProp(context, rawProps, sourceProps.yogaStyle); - - if (!CoreFeatures::enablePropIteratorSetter) { - convertRawPropAliases(context, sourceProps, rawProps); - } + if (!CoreFeatures::enablePropIteratorSetter) { + convertRawPropAliases(context, sourceProps, rawProps); } }; +/*static*/ const yoga::Style& YogaStylableProps::defaultStyle() { + static const auto defaultStyle = []() { + yoga::Style style; + style.setPositionType( + CoreFeatures::positionRelativeDefault ? yoga::PositionType::Relative + : yoga::PositionType::Static); + return style; + }(); + + return defaultStyle; +} + template static inline T const getFieldValue( const PropsParserContext& context, @@ -164,114 +61,116 @@ static inline T const getFieldValue( return defaultValue; } -#define REBUILD_FIELD_SWITCH_CASE2(field, fieldName) \ - case CONSTEXPR_RAW_PROPS_KEY_HASH(fieldName): { \ - yogaStyle.field() = getFieldValue(context, value, ygDefaults.field()); \ - return; \ +#define REBUILD_FIELD_SWITCH_CASE2(field, setter, fieldName) \ + case CONSTEXPR_RAW_PROPS_KEY_HASH(fieldName): { \ + yogaStyle.setter(getFieldValue(context, value, defaultStyle().field())); \ + return; \ } -// @lint-ignore CLANGTIDY cppcoreguidelines-macro-usage -#define REBUILD_FIELD_SWITCH_CASE_YSP(field) \ - REBUILD_FIELD_SWITCH_CASE2(field, #field) - -#define REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, index, fieldName) \ - case CONSTEXPR_RAW_PROPS_KEY_HASH(fieldName): { \ - yogaStyle.field()[index] = \ - getFieldValue(context, value, ygDefaults.field()[index]); \ - return; \ - } +#define REBUILD_FIELD_SWITCH_CASE_YSP(field, setter) \ + REBUILD_FIELD_SWITCH_CASE2(field, setter, #field) -#define REBUILD_YG_FIELD_SWITCH_CASE_INDEXED_SETTER( \ - field, setter, index, fieldName) \ - case CONSTEXPR_RAW_PROPS_KEY_HASH(fieldName): { \ - yogaStyle.setter( \ - index, getFieldValue(context, value, ygDefaults.field(index))); \ - return; \ +#define REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, setter, index, fieldName) \ + case CONSTEXPR_RAW_PROPS_KEY_HASH(fieldName): { \ + yogaStyle.setter( \ + index, getFieldValue(context, value, defaultStyle().field(index))); \ + return; \ } #define REBUILD_FIELD_YG_DIMENSION(field, setter, widthStr, heightStr) \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED_SETTER( \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ field, setter, yoga::Dimension::Width, widthStr); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED_SETTER( \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ field, setter, yoga::Dimension::Height, heightStr); #define REBUILD_FIELD_YG_GUTTER( \ field, setter, rowGapStr, columnGapStr, gapStr) \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED_SETTER( \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ field, setter, yoga::Gutter::Row, rowGapStr); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED_SETTER( \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ field, setter, yoga::Gutter::Column, columnGapStr); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED_SETTER( \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ field, setter, yoga::Gutter::All, gapStr); -#define REBUILD_FIELD_YG_EDGES(field, prefix, suffix) \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ - field, YGEdgeLeft, prefix "Left" suffix); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, YGEdgeTop, prefix "Top" suffix); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ - field, YGEdgeRight, prefix "Right" suffix); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ - field, YGEdgeBottom, prefix "Bottom" suffix); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ - field, YGEdgeStart, prefix "Start" suffix); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, YGEdgeEnd, prefix "End" suffix); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ - field, YGEdgeHorizontal, prefix "Horizontal" suffix); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ - field, YGEdgeVertical, prefix "Vertical" suffix); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, YGEdgeAll, prefix "" suffix); - -#define REBUILD_FIELD_YG_EDGES_POSITION() \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(position, YGEdgeLeft, "left"); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(position, YGEdgeTop, "top"); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(position, YGEdgeRight, "right"); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(position, YGEdgeBottom, "bottom"); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(position, YGEdgeStart, "start"); \ - REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(position, YGEdgeEnd, "end"); +#define REBUILD_FIELD_YG_EDGES(field, setter, prefix, suffix) \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + field, setter, yoga::Edge::Left, prefix "Left" suffix); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + field, setter, yoga::Edge::Top, prefix "Top" suffix); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + field, setter, yoga::Edge::Right, prefix "Right" suffix); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + field, setter, yoga::Edge::Bottom, prefix "Bottom" suffix); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + field, setter, yoga::Edge::Start, prefix "Start" suffix); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + field, setter, yoga::Edge::End, prefix "End" suffix); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + field, setter, yoga::Edge::Horizontal, prefix "Horizontal" suffix); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + field, setter, yoga::Edge::Vertical, prefix "Vertical" suffix); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + field, setter, yoga::Edge::All, prefix "" suffix); + +#define REBUILD_FIELD_YG_EDGES_POSITION() \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + position, setPosition, yoga::Edge::Left, "left"); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + position, setPosition, yoga::Edge::Top, "top"); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + position, setPosition, yoga::Edge::Right, "right"); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + position, setPosition, yoga::Edge::Bottom, "bottom"); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + position, setPosition, yoga::Edge::Start, "start"); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + position, setPosition, yoga::Edge::End, "end"); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + position, setPosition, yoga::Edge::Horizontal, "insetInline"); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + position, setPosition, yoga::Edge::Vertical, "insetBlock"); \ + REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \ + position, setPosition, yoga::Edge::All, "inset"); void YogaStylableProps::setProp( const PropsParserContext& context, RawPropsPropNameHash hash, const char* propName, const RawValue& value) { - static const auto ygDefaults = yoga::Style{}; static const auto defaults = YogaStylableProps{}; Props::setProp(context, hash, propName, value); switch (hash) { - REBUILD_FIELD_SWITCH_CASE_YSP(direction); - REBUILD_FIELD_SWITCH_CASE_YSP(flexDirection); - REBUILD_FIELD_SWITCH_CASE_YSP(justifyContent); - REBUILD_FIELD_SWITCH_CASE_YSP(alignContent); - REBUILD_FIELD_SWITCH_CASE_YSP(alignItems); - REBUILD_FIELD_SWITCH_CASE_YSP(alignSelf); - REBUILD_FIELD_SWITCH_CASE_YSP(flexWrap); - REBUILD_FIELD_SWITCH_CASE_YSP(overflow); - REBUILD_FIELD_SWITCH_CASE_YSP(display); - REBUILD_FIELD_SWITCH_CASE_YSP(flex); - REBUILD_FIELD_SWITCH_CASE_YSP(flexGrow); - REBUILD_FIELD_SWITCH_CASE_YSP(flexShrink); - REBUILD_FIELD_SWITCH_CASE_YSP(flexBasis); - REBUILD_FIELD_SWITCH_CASE2(positionType, "position"); + REBUILD_FIELD_SWITCH_CASE_YSP(direction, setDirection); + REBUILD_FIELD_SWITCH_CASE_YSP(flexDirection, setFlexDirection); + REBUILD_FIELD_SWITCH_CASE_YSP(justifyContent, setJustifyContent); + REBUILD_FIELD_SWITCH_CASE_YSP(alignContent, setAlignContent); + REBUILD_FIELD_SWITCH_CASE_YSP(alignItems, setAlignItems); + REBUILD_FIELD_SWITCH_CASE_YSP(alignSelf, setAlignSelf); + REBUILD_FIELD_SWITCH_CASE_YSP(flexWrap, setFlexWrap); + REBUILD_FIELD_SWITCH_CASE_YSP(overflow, setOverflow); + REBUILD_FIELD_SWITCH_CASE_YSP(display, setDisplay); + REBUILD_FIELD_SWITCH_CASE_YSP(flex, setFlex); + REBUILD_FIELD_SWITCH_CASE_YSP(flexGrow, setFlexGrow); + REBUILD_FIELD_SWITCH_CASE_YSP(flexShrink, setFlexShrink); + REBUILD_FIELD_SWITCH_CASE_YSP(flexBasis, setFlexBasis); + REBUILD_FIELD_SWITCH_CASE2(positionType, setPositionType, "position"); REBUILD_FIELD_YG_GUTTER(gap, setGap, "rowGap", "columnGap", "gap"); - REBUILD_FIELD_SWITCH_CASE_YSP(aspectRatio); + REBUILD_FIELD_SWITCH_CASE_YSP(aspectRatio, setAspectRatio); REBUILD_FIELD_YG_DIMENSION(dimension, setDimension, "width", "height"); REBUILD_FIELD_YG_DIMENSION( minDimension, setMinDimension, "minWidth", "minHeight"); REBUILD_FIELD_YG_DIMENSION( maxDimension, setMaxDimension, "maxWidth", "maxHeight"); REBUILD_FIELD_YG_EDGES_POSITION(); - REBUILD_FIELD_YG_EDGES(margin, "margin", ""); - REBUILD_FIELD_YG_EDGES(padding, "padding", ""); - REBUILD_FIELD_YG_EDGES(border, "border", "Width"); + REBUILD_FIELD_YG_EDGES(margin, setMargin, "margin", ""); + REBUILD_FIELD_YG_EDGES(padding, setPadding, "padding", ""); + REBUILD_FIELD_YG_EDGES(border, setBorder, "border", "Width"); // Aliases - RAW_SET_PROP_SWITCH_CASE(inset, "inset"); - RAW_SET_PROP_SWITCH_CASE(insetBlock, "insetBlock"); RAW_SET_PROP_SWITCH_CASE(insetBlockEnd, "insetBlockEnd"); RAW_SET_PROP_SWITCH_CASE(insetBlockStart, "insetBlockStart"); - RAW_SET_PROP_SWITCH_CASE(insetInline, "insetInline"); RAW_SET_PROP_SWITCH_CASE(insetInlineEnd, "insetInlineEnd"); RAW_SET_PROP_SWITCH_CASE(insetInlineStart, "insetInlineStart"); RAW_SET_PROP_SWITCH_CASE(marginInline, "marginInline"); @@ -293,92 +192,225 @@ void YogaStylableProps::setProp( #if RN_DEBUG_STRING_CONVERTIBLE SharedDebugStringConvertibleList YogaStylableProps::getDebugProps() const { - const auto defaultYogaStyle = yoga::Style{}; return { debugStringConvertibleItem( - "direction", yogaStyle.direction(), defaultYogaStyle.direction()), + "direction", yogaStyle.direction(), defaultStyle().direction()), debugStringConvertibleItem( "flexDirection", yogaStyle.flexDirection(), - defaultYogaStyle.flexDirection()), + defaultStyle().flexDirection()), debugStringConvertibleItem( "justifyContent", yogaStyle.justifyContent(), - defaultYogaStyle.justifyContent()), + defaultStyle().justifyContent()), debugStringConvertibleItem( "alignContent", yogaStyle.alignContent(), - defaultYogaStyle.alignContent()), + defaultStyle().alignContent()), debugStringConvertibleItem( - "alignItems", yogaStyle.alignItems(), defaultYogaStyle.alignItems()), + "alignItems", yogaStyle.alignItems(), defaultStyle().alignItems()), debugStringConvertibleItem( - "alignSelf", yogaStyle.alignSelf(), defaultYogaStyle.alignSelf()), + "alignSelf", yogaStyle.alignSelf(), defaultStyle().alignSelf()), debugStringConvertibleItem( "positionType", yogaStyle.positionType(), - defaultYogaStyle.positionType()), + defaultStyle().positionType()), debugStringConvertibleItem( - "flexWrap", yogaStyle.flexWrap(), defaultYogaStyle.flexWrap()), + "flexWrap", yogaStyle.flexWrap(), defaultStyle().flexWrap()), debugStringConvertibleItem( - "overflow", yogaStyle.overflow(), defaultYogaStyle.overflow()), + "overflow", yogaStyle.overflow(), defaultStyle().overflow()), debugStringConvertibleItem( - "display", yogaStyle.display(), defaultYogaStyle.display()), + "display", yogaStyle.display(), defaultStyle().display()), debugStringConvertibleItem( - "flex", yogaStyle.flex(), defaultYogaStyle.flex()), + "flex", yogaStyle.flex(), defaultStyle().flex()), debugStringConvertibleItem( - "flexGrow", yogaStyle.flexGrow(), defaultYogaStyle.flexGrow()), + "flexGrow", yogaStyle.flexGrow(), defaultStyle().flexGrow()), debugStringConvertibleItem( "rowGap", yogaStyle.gap(yoga::Gutter::Row), - defaultYogaStyle.gap(yoga::Gutter::Row)), + defaultStyle().gap(yoga::Gutter::Row)), debugStringConvertibleItem( "columnGap", yogaStyle.gap(yoga::Gutter::Column), - defaultYogaStyle.gap(yoga::Gutter::Column)), + defaultStyle().gap(yoga::Gutter::Column)), debugStringConvertibleItem( "gap", yogaStyle.gap(yoga::Gutter::All), - defaultYogaStyle.gap(yoga::Gutter::All)), + defaultStyle().gap(yoga::Gutter::All)), + debugStringConvertibleItem( + "flexShrink", yogaStyle.flexShrink(), defaultStyle().flexShrink()), + debugStringConvertibleItem( + "flexBasis", yogaStyle.flexBasis(), defaultStyle().flexBasis()), + debugStringConvertibleItem( + "marginLeft", + yogaStyle.margin(yoga::Edge::Left), + defaultStyle().margin(yoga::Edge::Left)), + debugStringConvertibleItem( + "marginTop", + yogaStyle.margin(yoga::Edge::Top), + defaultStyle().margin(yoga::Edge::Top)), + debugStringConvertibleItem( + "marginRight", + yogaStyle.margin(yoga::Edge::Right), + defaultStyle().margin(yoga::Edge::Right)), + debugStringConvertibleItem( + "marginBottom", + yogaStyle.margin(yoga::Edge::Bottom), + defaultStyle().margin(yoga::Edge::Bottom)), + debugStringConvertibleItem( + "marginStart", + yogaStyle.margin(yoga::Edge::Start), + defaultStyle().margin(yoga::Edge::Start)), + debugStringConvertibleItem( + "marginEnd", + yogaStyle.margin(yoga::Edge::End), + defaultStyle().margin(yoga::Edge::End)), + debugStringConvertibleItem( + "marginHorizontal", + yogaStyle.margin(yoga::Edge::Horizontal), + defaultStyle().margin(yoga::Edge::Horizontal)), + debugStringConvertibleItem( + "marginVertical", + yogaStyle.margin(yoga::Edge::Vertical), + defaultStyle().margin(yoga::Edge::Vertical)), debugStringConvertibleItem( - "flexShrink", yogaStyle.flexShrink(), defaultYogaStyle.flexShrink()), + "margin", + yogaStyle.margin(yoga::Edge::All), + defaultStyle().margin(yoga::Edge::All)), debugStringConvertibleItem( - "flexBasis", yogaStyle.flexBasis(), defaultYogaStyle.flexBasis()), + "left", + yogaStyle.position(yoga::Edge::Left), + defaultStyle().position(yoga::Edge::Left)), debugStringConvertibleItem( - "margin", yogaStyle.margin(), defaultYogaStyle.margin()), + "top", + yogaStyle.position(yoga::Edge::Top), + defaultStyle().position(yoga::Edge::Top)), debugStringConvertibleItem( - "position", yogaStyle.position(), defaultYogaStyle.position()), + "right", + yogaStyle.position(yoga::Edge::Right), + defaultStyle().position(yoga::Edge::Right)), debugStringConvertibleItem( - "padding", yogaStyle.padding(), defaultYogaStyle.padding()), + "bottom", + yogaStyle.position(yoga::Edge::Bottom), + defaultStyle().position(yoga::Edge::Bottom)), debugStringConvertibleItem( - "border", yogaStyle.border(), defaultYogaStyle.border()), + "start", + yogaStyle.position(yoga::Edge::Start), + defaultStyle().position(yoga::Edge::Start)), + debugStringConvertibleItem( + "end", + yogaStyle.position(yoga::Edge::End), + defaultStyle().position(yoga::Edge::End)), + debugStringConvertibleItem( + "inseInline", + yogaStyle.position(yoga::Edge::Horizontal), + defaultStyle().position(yoga::Edge::Horizontal)), + debugStringConvertibleItem( + "insetBlock", + yogaStyle.position(yoga::Edge::Vertical), + defaultStyle().position(yoga::Edge::Vertical)), + debugStringConvertibleItem( + "inset", + yogaStyle.position(yoga::Edge::All), + defaultStyle().position(yoga::Edge::All)), + debugStringConvertibleItem( + "paddingLeft", + yogaStyle.padding(yoga::Edge::Left), + defaultStyle().padding(yoga::Edge::Left)), + debugStringConvertibleItem( + "paddingTop", + yogaStyle.padding(yoga::Edge::Top), + defaultStyle().padding(yoga::Edge::Top)), + debugStringConvertibleItem( + "paddingRight", + yogaStyle.padding(yoga::Edge::Right), + defaultStyle().padding(yoga::Edge::Right)), + debugStringConvertibleItem( + "paddingBottom", + yogaStyle.padding(yoga::Edge::Bottom), + defaultStyle().padding(yoga::Edge::Bottom)), + debugStringConvertibleItem( + "paddingStart", + yogaStyle.padding(yoga::Edge::Start), + defaultStyle().padding(yoga::Edge::Start)), + debugStringConvertibleItem( + "paddingEnd", + yogaStyle.padding(yoga::Edge::End), + defaultStyle().padding(yoga::Edge::End)), + debugStringConvertibleItem( + "paddingHorizontal", + yogaStyle.padding(yoga::Edge::Horizontal), + defaultStyle().padding(yoga::Edge::Horizontal)), + debugStringConvertibleItem( + "paddingVertical", + yogaStyle.padding(yoga::Edge::Vertical), + defaultStyle().padding(yoga::Edge::Vertical)), + debugStringConvertibleItem( + "padding", + yogaStyle.padding(yoga::Edge::All), + defaultStyle().padding(yoga::Edge::All)), + debugStringConvertibleItem( + "borderLeftWidth", + yogaStyle.border(yoga::Edge::Left), + defaultStyle().border(yoga::Edge::Left)), + debugStringConvertibleItem( + "borderTopWidth", + yogaStyle.border(yoga::Edge::Top), + defaultStyle().border(yoga::Edge::Top)), + debugStringConvertibleItem( + "borderRightWidth", + yogaStyle.border(yoga::Edge::Right), + defaultStyle().border(yoga::Edge::Right)), + debugStringConvertibleItem( + "borderBottomWidth", + yogaStyle.border(yoga::Edge::Bottom), + defaultStyle().border(yoga::Edge::Bottom)), + debugStringConvertibleItem( + "borderStartWidth", + yogaStyle.border(yoga::Edge::Start), + defaultStyle().border(yoga::Edge::Start)), + debugStringConvertibleItem( + "borderEndWidth", + yogaStyle.border(yoga::Edge::End), + defaultStyle().border(yoga::Edge::End)), + debugStringConvertibleItem( + "borderHorizontalWidth", + yogaStyle.border(yoga::Edge::Horizontal), + defaultStyle().border(yoga::Edge::Horizontal)), + debugStringConvertibleItem( + "borderVerticalWidth", + yogaStyle.border(yoga::Edge::Vertical), + defaultStyle().border(yoga::Edge::Vertical)), + debugStringConvertibleItem( + "bordeWidth", + yogaStyle.border(yoga::Edge::All), + defaultStyle().border(yoga::Edge::All)), debugStringConvertibleItem( "width", yogaStyle.dimension(yoga::Dimension::Width), - defaultYogaStyle.dimension(yoga::Dimension::Width)), + defaultStyle().dimension(yoga::Dimension::Width)), debugStringConvertibleItem( "height", yogaStyle.dimension(yoga::Dimension::Height), - defaultYogaStyle.dimension(yoga::Dimension::Height)), + defaultStyle().dimension(yoga::Dimension::Height)), debugStringConvertibleItem( "minWidth", yogaStyle.minDimension(yoga::Dimension::Width), - defaultYogaStyle.minDimension(yoga::Dimension::Width)), + defaultStyle().minDimension(yoga::Dimension::Width)), debugStringConvertibleItem( "minHeight", yogaStyle.minDimension(yoga::Dimension::Height), - defaultYogaStyle.minDimension(yoga::Dimension::Height)), + defaultStyle().minDimension(yoga::Dimension::Height)), debugStringConvertibleItem( "maxWidth", yogaStyle.maxDimension(yoga::Dimension::Width), - defaultYogaStyle.maxDimension(yoga::Dimension::Width)), + defaultStyle().maxDimension(yoga::Dimension::Width)), debugStringConvertibleItem( "maxHeight", yogaStyle.maxDimension(yoga::Dimension::Height), - defaultYogaStyle.maxDimension(yoga::Dimension::Height)), + defaultStyle().maxDimension(yoga::Dimension::Height)), debugStringConvertibleItem( - "aspectRatio", - yogaStyle.aspectRatio(), - defaultYogaStyle.aspectRatio()), + "aspectRatio", yogaStyle.aspectRatio(), defaultStyle().aspectRatio()), }; } #endif @@ -387,121 +419,103 @@ void YogaStylableProps::convertRawPropAliases( const PropsParserContext& context, const YogaStylableProps& sourceProps, const RawProps& rawProps) { - inset = convertRawProp( - context, - rawProps, - "inset", - sourceProps.inset, - CompactValue::ofUndefined()); - insetBlock = convertRawProp( - context, - rawProps, - "insetBlock", - sourceProps.insetBlock, - CompactValue::ofUndefined()); insetBlockEnd = convertRawProp( context, rawProps, "insetBlockEnd", sourceProps.insetBlockEnd, - CompactValue::ofUndefined()); + yoga::value::undefined()); insetBlockStart = convertRawProp( context, rawProps, "insetBlockStart", sourceProps.insetBlockStart, - CompactValue::ofUndefined()); - insetInline = convertRawProp( - context, - rawProps, - "insetInline", - sourceProps.insetInline, - CompactValue::ofUndefined()); + yoga::value::undefined()); insetInlineEnd = convertRawProp( context, rawProps, "insetInlineEnd", sourceProps.insetInlineEnd, - CompactValue::ofUndefined()); + yoga::value::undefined()); insetInlineStart = convertRawProp( context, rawProps, "insetInlineStart", sourceProps.insetInlineStart, - CompactValue::ofUndefined()); + yoga::value::undefined()); marginInline = convertRawProp( context, rawProps, "marginInline", sourceProps.marginInline, - CompactValue::ofUndefined()); + yoga::value::undefined()); marginInlineStart = convertRawProp( context, rawProps, "marginInlineStart", sourceProps.marginInlineStart, - CompactValue::ofUndefined()); + yoga::value::undefined()); marginInlineEnd = convertRawProp( context, rawProps, "marginInlineEnd", sourceProps.marginInlineEnd, - CompactValue::ofUndefined()); + yoga::value::undefined()); marginBlock = convertRawProp( context, rawProps, "marginBlock", sourceProps.marginBlock, - CompactValue::ofUndefined()); + yoga::value::undefined()); marginBlockStart = convertRawProp( context, rawProps, "marginBlockStart", sourceProps.marginBlockStart, - CompactValue::ofUndefined()); + yoga::value::undefined()); marginBlockEnd = convertRawProp( context, rawProps, "marginBlockEnd", sourceProps.marginBlockEnd, - CompactValue::ofUndefined()); + yoga::value::undefined()); paddingInline = convertRawProp( context, rawProps, "paddingInline", sourceProps.paddingInline, - CompactValue::ofUndefined()); + yoga::value::undefined()); paddingInlineStart = convertRawProp( context, rawProps, "paddingInlineStart", sourceProps.paddingInlineStart, - CompactValue::ofUndefined()); + yoga::value::undefined()); paddingInlineEnd = convertRawProp( context, rawProps, "paddingInlineEnd", sourceProps.paddingInlineEnd, - CompactValue::ofUndefined()); + yoga::value::undefined()); paddingBlock = convertRawProp( context, rawProps, "paddingBlock", sourceProps.paddingBlock, - CompactValue::ofUndefined()); + yoga::value::undefined()); paddingBlockStart = convertRawProp( context, rawProps, "paddingBlockStart", sourceProps.paddingBlockStart, - CompactValue::ofUndefined()); + yoga::value::undefined()); paddingBlockEnd = convertRawProp( context, rawProps, "paddingBlockEnd", sourceProps.paddingBlockEnd, - CompactValue::ofUndefined()); + yoga::value::undefined()); } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/YogaStylableProps.h b/packages/react-native/ReactCommon/react/renderer/components/view/YogaStylableProps.h index 6b529f7a7180fd..fea1c2609e2272 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/YogaStylableProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/YogaStylableProps.h @@ -16,8 +16,6 @@ namespace facebook::react { class YogaStylableProps : public Props { - using CompactValue = facebook::yoga::CompactValue; - public: YogaStylableProps() = default; YogaStylableProps( @@ -25,6 +23,8 @@ class YogaStylableProps : public Props { const YogaStylableProps& sourceProps, const RawProps& rawProps); + static const yoga::Style& defaultStyle(); + void setProp( const PropsParserContext& context, RawPropsPropNameHash hash, @@ -37,37 +37,34 @@ class YogaStylableProps : public Props { #endif #pragma mark - Props - yoga::Style yogaStyle{}; + yoga::Style yogaStyle{defaultStyle()}; // Duplicates of existing properties with different names, taking // precedence. E.g. "marginBlock" instead of "marginVertical" - CompactValue inset; - CompactValue insetInline; - CompactValue insetInlineEnd; - CompactValue insetInlineStart; + yoga::Style::Length insetInlineStart; + yoga::Style::Length insetInlineEnd; - CompactValue marginInline; - CompactValue marginInlineStart; - CompactValue marginInlineEnd; - CompactValue marginBlock; + yoga::Style::Length marginInline; + yoga::Style::Length marginInlineStart; + yoga::Style::Length marginInlineEnd; + yoga::Style::Length marginBlock; - CompactValue paddingInline; - CompactValue paddingInlineStart; - CompactValue paddingInlineEnd; - CompactValue paddingBlock; + yoga::Style::Length paddingInline; + yoga::Style::Length paddingInlineStart; + yoga::Style::Length paddingInlineEnd; + yoga::Style::Length paddingBlock; // BlockEnd/BlockStart map to top/bottom (no writing mode), but we preserve // Yoga's precedence and prefer specific edges (e.g. top) to ones which are // flow relative (e.g. blockStart). - CompactValue insetBlock; - CompactValue insetBlockEnd; - CompactValue insetBlockStart; + yoga::Style::Length insetBlockStart; + yoga::Style::Length insetBlockEnd; - CompactValue marginBlockStart; - CompactValue marginBlockEnd; + yoga::Style::Length marginBlockStart; + yoga::Style::Length marginBlockEnd; - CompactValue paddingBlockStart; - CompactValue paddingBlockEnd; + yoga::Style::Length paddingBlockStart; + yoga::Style::Length paddingBlockEnd; #if RN_DEBUG_STRING_CONVERTIBLE diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h b/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h index c0edf7ce02dde9..58a898fb1027d1 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h @@ -395,9 +395,9 @@ inline void fromRawValue( inline void fromRawValue( const PropsParserContext& context, const RawValue& value, - yoga::Style::ValueRepr& result) { + yoga::Style::Length& result) { if (value.hasType()) { - result = yoga::CompactValue::ofMaybe((float)value); + result = yoga::value::points((float)value); return; } else if (value.hasType()) { const auto stringValue = (std::string)value; @@ -409,13 +409,13 @@ inline void fromRawValue( auto tryValue = folly::tryTo( std::string_view(stringValue).substr(0, stringValue.length() - 1)); if (tryValue.hasValue()) { - result = YGValue{tryValue.value(), YGUnitPercent}; + result = yoga::value::percent(tryValue.value()); return; } } else { auto tryValue = folly::tryTo(stringValue); if (tryValue.hasValue()) { - result = YGValue{tryValue.value(), YGUnitPoint}; + result = yoga::value::points(tryValue.value()); return; } } @@ -428,7 +428,7 @@ inline void fromRawValue( const PropsParserContext& context, const RawValue& value, YGValue& result) { - yoga::Style::ValueRepr ygValue{}; + yoga::Style::Length ygValue{}; fromRawValue(context, value, ygValue); result = ygValue; } @@ -778,40 +778,6 @@ inline std::string toString(const yoga::FloatOptional& value) { return folly::to(floatFromYogaFloat(value.unwrap())); } -inline std::string toString(const yoga::Style::Dimensions& value) { - return "{" + toString(value[0]) + ", " + toString(value[1]) + "}"; -} - -inline std::string toString(const yoga::Style::Edges& value) { - static std::array names = { - {"left", - "top", - "right", - "bottom", - "start", - "end", - "horizontal", - "vertical", - "all"}}; - - auto result = std::string{}; - auto separator = std::string{", "}; - - for (size_t i = 0; i < names.size(); i++) { - YGValue v = value[i]; - if (v.unit == YGUnitUndefined) { - continue; - } - result += names[i] + ": " + toString(v) + separator; - } - - if (!result.empty()) { - result.erase(result.length() - separator.length()); - } - - return "{" + result + "}"; -} - inline std::string toString(const LayoutConformance& value) { switch (value) { case LayoutConformance::Undefined: diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/YogaStylablePropsMapBuffer.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/YogaStylablePropsMapBuffer.cpp index 640a407caec03b..20474d7ec37a4f 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/YogaStylablePropsMapBuffer.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/YogaStylablePropsMapBuffer.cpp @@ -13,22 +13,36 @@ namespace facebook::react { -MapBuffer convertBorderWidths(const yoga::Style::Edges& border) { +MapBuffer convertBorderWidths(const yoga::Style& style) { MapBufferBuilder builder(7); putOptionalFloat( - builder, EDGE_TOP, optionalFloatFromYogaValue(border[YGEdgeTop])); + builder, + EDGE_TOP, + optionalFloatFromYogaValue(style.border(yoga::Edge::Top))); putOptionalFloat( - builder, EDGE_RIGHT, optionalFloatFromYogaValue(border[YGEdgeRight])); + builder, + EDGE_RIGHT, + optionalFloatFromYogaValue(style.border(yoga::Edge::Right))); putOptionalFloat( - builder, EDGE_BOTTOM, optionalFloatFromYogaValue(border[YGEdgeBottom])); + builder, + EDGE_BOTTOM, + optionalFloatFromYogaValue(style.border(yoga::Edge::Bottom))); putOptionalFloat( - builder, EDGE_LEFT, optionalFloatFromYogaValue(border[YGEdgeLeft])); + builder, + EDGE_LEFT, + optionalFloatFromYogaValue(style.border(yoga::Edge::Left))); putOptionalFloat( - builder, EDGE_START, optionalFloatFromYogaValue(border[YGEdgeStart])); + builder, + EDGE_START, + optionalFloatFromYogaValue(style.border(yoga::Edge::Start))); putOptionalFloat( - builder, EDGE_END, optionalFloatFromYogaValue(border[YGEdgeEnd])); + builder, + EDGE_END, + optionalFloatFromYogaValue(style.border(yoga::Edge::End))); putOptionalFloat( - builder, EDGE_ALL, optionalFloatFromYogaValue(border[YGEdgeAll])); + builder, + EDGE_ALL, + optionalFloatFromYogaValue(style.border(yoga::Edge::All))); return builder.build(); } @@ -54,9 +68,16 @@ void YogaStylableProps::propsDiffMapBuffer( const auto& oldStyle = oldProps.yogaStyle; const auto& newStyle = newProps.yogaStyle; - if (!(oldStyle.border() == newStyle.border())) { - builder.putMapBuffer( - YG_BORDER_WIDTH, convertBorderWidths(newStyle.border())); + bool areBordersEqual = true; + for (auto edge : yoga::ordinals()) { + if (oldStyle.border(edge) != newStyle.border(edge)) { + areBordersEqual = false; + break; + } + } + + if (!areBordersEqual) { + builder.putMapBuffer(YG_BORDER_WIDTH, convertBorderWidths(newStyle)); } if (oldStyle.overflow() != newStyle.overflow()) { diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h b/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h index db085aa2ae566d..df078b1dd23cc6 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include @@ -18,231 +19,348 @@ namespace facebook::react { // Nearly this entire file can be deleted when iterator-style Prop parsing // ships fully for View -static inline yoga::Style::Edges convertRawProp( - const PropsParserContext& context, - const RawProps& rawProps, - const char* prefix, - const char* suffix, - const yoga::Style::Edges& sourceValue, - const yoga::Style::Edges& defaultValue) { - auto result = defaultValue; - result[YGEdgeLeft] = convertRawProp( - context, - rawProps, - "Left", - sourceValue[YGEdgeLeft], - defaultValue[YGEdgeLeft], - prefix, - suffix); - result[YGEdgeTop] = convertRawProp( - context, - rawProps, - "Top", - sourceValue[YGEdgeTop], - defaultValue[YGEdgeTop], - prefix, - suffix); - result[YGEdgeRight] = convertRawProp( - context, - rawProps, - "Right", - sourceValue[YGEdgeRight], - defaultValue[YGEdgeRight], - prefix, - suffix); - result[YGEdgeBottom] = convertRawProp( - context, - rawProps, - "Bottom", - sourceValue[YGEdgeBottom], - defaultValue[YGEdgeBottom], - prefix, - suffix); - result[YGEdgeStart] = convertRawProp( - context, - rawProps, - "Start", - sourceValue[YGEdgeStart], - defaultValue[YGEdgeStart], - prefix, - suffix); - result[YGEdgeEnd] = convertRawProp( - context, - rawProps, - "End", - sourceValue[YGEdgeEnd], - defaultValue[YGEdgeEnd], - prefix, - suffix); - result[YGEdgeHorizontal] = convertRawProp( - context, - rawProps, - "Horizontal", - sourceValue[YGEdgeHorizontal], - defaultValue[YGEdgeHorizontal], - prefix, - suffix); - result[YGEdgeVertical] = convertRawProp( - context, - rawProps, - "Vertical", - sourceValue[YGEdgeVertical], - defaultValue[YGEdgeVertical], - prefix, - suffix); - result[YGEdgeAll] = convertRawProp( - context, - rawProps, - "", - sourceValue[YGEdgeAll], - defaultValue[YGEdgeAll], - prefix, - suffix); - return result; -} - -static inline yoga::Style::Edges convertRawProp( - const PropsParserContext& context, - const RawProps& rawProps, - const yoga::Style::Edges& sourceValue, - const yoga::Style::Edges& defaultValue) { - auto result = defaultValue; - result[YGEdgeLeft] = convertRawProp( - context, - rawProps, - "left", - sourceValue[YGEdgeLeft], - defaultValue[YGEdgeLeft]); - result[YGEdgeTop] = convertRawProp( - context, - rawProps, - "top", - sourceValue[YGEdgeTop], - defaultValue[YGEdgeTop]); - result[YGEdgeRight] = convertRawProp( - context, - rawProps, - "right", - sourceValue[YGEdgeRight], - defaultValue[YGEdgeRight]); - result[YGEdgeBottom] = convertRawProp( - context, - rawProps, - "bottom", - sourceValue[YGEdgeBottom], - defaultValue[YGEdgeBottom]); - result[YGEdgeStart] = convertRawProp( - context, - rawProps, - "start", - sourceValue[YGEdgeStart], - defaultValue[YGEdgeStart]); - result[YGEdgeEnd] = convertRawProp( - context, - rawProps, - "end", - sourceValue[YGEdgeEnd], - defaultValue[YGEdgeEnd]); - return result; -} - static inline yoga::Style convertRawProp( const PropsParserContext& context, const RawProps& rawProps, const yoga::Style& sourceValue) { - yoga::Style yogaStyle{}; - yogaStyle.direction() = convertRawProp( + auto yogaStyle = YogaStylableProps::defaultStyle(); + + yogaStyle.setDirection(convertRawProp( context, rawProps, "direction", sourceValue.direction(), - yogaStyle.direction()); - yogaStyle.flexDirection() = convertRawProp( + yogaStyle.direction())); + + yogaStyle.setFlexDirection(convertRawProp( context, rawProps, "flexDirection", sourceValue.flexDirection(), - yogaStyle.flexDirection()); - yogaStyle.justifyContent() = convertRawProp( + yogaStyle.flexDirection())); + + yogaStyle.setJustifyContent(convertRawProp( context, rawProps, "justifyContent", sourceValue.justifyContent(), - yogaStyle.justifyContent()); - yogaStyle.alignContent() = convertRawProp( + yogaStyle.justifyContent())); + + yogaStyle.setAlignContent(convertRawProp( context, rawProps, "alignContent", sourceValue.alignContent(), - yogaStyle.alignContent()); - yogaStyle.alignItems() = convertRawProp( + yogaStyle.alignContent())); + + yogaStyle.setAlignItems(convertRawProp( context, rawProps, "alignItems", sourceValue.alignItems(), - yogaStyle.alignItems()); - yogaStyle.alignSelf() = convertRawProp( + yogaStyle.alignItems())); + + yogaStyle.setAlignSelf(convertRawProp( context, rawProps, "alignSelf", sourceValue.alignSelf(), - yogaStyle.alignSelf()); - yogaStyle.positionType() = convertRawProp( + yogaStyle.alignSelf())); + + yogaStyle.setPositionType(convertRawProp( context, rawProps, "position", sourceValue.positionType(), - yogaStyle.positionType()); - yogaStyle.flexWrap() = convertRawProp( + yogaStyle.positionType())); + + yogaStyle.setFlexWrap(convertRawProp( context, rawProps, "flexWrap", sourceValue.flexWrap(), - yogaStyle.flexWrap()); - yogaStyle.overflow() = convertRawProp( + yogaStyle.flexWrap())); + + yogaStyle.setOverflow(convertRawProp( context, rawProps, "overflow", sourceValue.overflow(), - yogaStyle.overflow()); - yogaStyle.display() = convertRawProp( - context, rawProps, "display", sourceValue.display(), yogaStyle.display()); - yogaStyle.flex() = convertRawProp( - context, rawProps, "flex", sourceValue.flex(), yogaStyle.flex()); - yogaStyle.flexGrow() = convertRawProp( + yogaStyle.overflow())); + + yogaStyle.setDisplay(convertRawProp( + context, + rawProps, + "display", + sourceValue.display(), + yogaStyle.display())); + + yogaStyle.setFlex(convertRawProp( + context, rawProps, "flex", sourceValue.flex(), yogaStyle.flex())); + + yogaStyle.setFlexGrow(convertRawProp( context, rawProps, "flexGrow", sourceValue.flexGrow(), - yogaStyle.flexGrow()); - yogaStyle.flexShrink() = convertRawProp( + yogaStyle.flexGrow())); + + yogaStyle.setFlexShrink(convertRawProp( context, rawProps, "flexShrink", sourceValue.flexShrink(), - yogaStyle.flexShrink()); - yogaStyle.flexBasis() = convertRawProp( + yogaStyle.flexShrink())); + + yogaStyle.setFlexBasis(convertRawProp( context, rawProps, "flexBasis", sourceValue.flexBasis(), - yogaStyle.flexBasis()); - yogaStyle.margin() = convertRawProp( - context, - rawProps, - "margin", - "", - sourceValue.margin(), - yogaStyle.margin()); - yogaStyle.position() = convertRawProp( - context, rawProps, sourceValue.position(), yogaStyle.position()); - yogaStyle.padding() = convertRawProp( - context, - rawProps, - "padding", - "", - sourceValue.padding(), - yogaStyle.padding()); + yogaStyle.flexBasis())); + + yogaStyle.setMargin( + yoga::Edge::Left, + convertRawProp( + context, + rawProps, + "marginLeft", + sourceValue.margin(yoga::Edge::Left), + yogaStyle.margin(yoga::Edge::Left))); + + yogaStyle.setMargin( + yoga::Edge::Top, + convertRawProp( + context, + rawProps, + "marginTop", + sourceValue.margin(yoga::Edge::Top), + yogaStyle.margin(yoga::Edge::Top))); + + yogaStyle.setMargin( + yoga::Edge::Right, + convertRawProp( + context, + rawProps, + "marginRight", + sourceValue.margin(yoga::Edge::Right), + yogaStyle.margin(yoga::Edge::Right))); + + yogaStyle.setMargin( + yoga::Edge::Bottom, + convertRawProp( + context, + rawProps, + "marginBottom", + sourceValue.margin(yoga::Edge::Bottom), + yogaStyle.margin(yoga::Edge::Bottom))); + + yogaStyle.setMargin( + yoga::Edge::Start, + convertRawProp( + context, + rawProps, + "marginStart", + sourceValue.margin(yoga::Edge::Start), + yogaStyle.margin(yoga::Edge::Start))); + + yogaStyle.setMargin( + yoga::Edge::End, + convertRawProp( + context, + rawProps, + "marginEnd", + sourceValue.margin(yoga::Edge::End), + yogaStyle.margin(yoga::Edge::End))); + + yogaStyle.setMargin( + yoga::Edge::Horizontal, + convertRawProp( + context, + rawProps, + "marginHorizontal", + sourceValue.margin(yoga::Edge::Horizontal), + yogaStyle.margin(yoga::Edge::Horizontal))); + + yogaStyle.setMargin( + yoga::Edge::Vertical, + convertRawProp( + context, + rawProps, + "marginVertical", + sourceValue.margin(yoga::Edge::Vertical), + yogaStyle.margin(yoga::Edge::Vertical))); + + yogaStyle.setMargin( + yoga::Edge::All, + convertRawProp( + context, + rawProps, + "margin", + sourceValue.margin(yoga::Edge::All), + yogaStyle.margin(yoga::Edge::All))); + + yogaStyle.setPosition( + yoga::Edge::Left, + convertRawProp( + context, + rawProps, + "left", + sourceValue.position(yoga::Edge::Left), + yogaStyle.position(yoga::Edge::Left))); + + yogaStyle.setPosition( + yoga::Edge::Top, + convertRawProp( + context, + rawProps, + "top", + sourceValue.position(yoga::Edge::Top), + yogaStyle.position(yoga::Edge::Top))); + + yogaStyle.setPosition( + yoga::Edge::Right, + convertRawProp( + context, + rawProps, + "right", + sourceValue.position(yoga::Edge::Right), + yogaStyle.position(yoga::Edge::Right))); + + yogaStyle.setPosition( + yoga::Edge::Bottom, + convertRawProp( + context, + rawProps, + "bottom", + sourceValue.position(yoga::Edge::Bottom), + yogaStyle.position(yoga::Edge::Bottom))); + + yogaStyle.setPosition( + yoga::Edge::Start, + convertRawProp( + context, + rawProps, + "start", + sourceValue.position(yoga::Edge::Start), + yogaStyle.position(yoga::Edge::Start))); + + yogaStyle.setPosition( + yoga::Edge::End, + convertRawProp( + context, + rawProps, + "end", + sourceValue.position(yoga::Edge::End), + yogaStyle.position(yoga::Edge::End))); + + yogaStyle.setPosition( + yoga::Edge::Horizontal, + convertRawProp( + context, + rawProps, + "insetInline", + sourceValue.position(yoga::Edge::Horizontal), + yogaStyle.position(yoga::Edge::Horizontal))); + + yogaStyle.setPosition( + yoga::Edge::Vertical, + convertRawProp( + context, + rawProps, + "insetBlock", + sourceValue.position(yoga::Edge::Vertical), + yogaStyle.position(yoga::Edge::Vertical))); + + yogaStyle.setPosition( + yoga::Edge::All, + convertRawProp( + context, + rawProps, + "inset", + sourceValue.position(yoga::Edge::All), + yogaStyle.position(yoga::Edge::All))); + + yogaStyle.setPadding( + yoga::Edge::Left, + convertRawProp( + context, + rawProps, + "paddingLeft", + sourceValue.padding(yoga::Edge::Left), + yogaStyle.padding(yoga::Edge::Left))); + + yogaStyle.setPadding( + yoga::Edge::Top, + convertRawProp( + context, + rawProps, + "paddingTop", + sourceValue.padding(yoga::Edge::Top), + yogaStyle.padding(yoga::Edge::Top))); + + yogaStyle.setPadding( + yoga::Edge::Right, + convertRawProp( + context, + rawProps, + "paddingRight", + sourceValue.padding(yoga::Edge::Right), + yogaStyle.padding(yoga::Edge::Right))); + + yogaStyle.setPadding( + yoga::Edge::Bottom, + convertRawProp( + context, + rawProps, + "paddingBottom", + sourceValue.padding(yoga::Edge::Bottom), + yogaStyle.padding(yoga::Edge::Bottom))); + + yogaStyle.setPadding( + yoga::Edge::Start, + convertRawProp( + context, + rawProps, + "paddingStart", + sourceValue.padding(yoga::Edge::Start), + yogaStyle.padding(yoga::Edge::Start))); + + yogaStyle.setPadding( + yoga::Edge::End, + convertRawProp( + context, + rawProps, + "paddingEnd", + sourceValue.padding(yoga::Edge::End), + yogaStyle.padding(yoga::Edge::End))); + + yogaStyle.setPadding( + yoga::Edge::Horizontal, + convertRawProp( + context, + rawProps, + "paddingHorizontal", + sourceValue.padding(yoga::Edge::Horizontal), + yogaStyle.padding(yoga::Edge::Horizontal))); + + yogaStyle.setPadding( + yoga::Edge::Vertical, + convertRawProp( + context, + rawProps, + "paddingVertical", + sourceValue.padding(yoga::Edge::Vertical), + yogaStyle.padding(yoga::Edge::Vertical))); + + yogaStyle.setPadding( + yoga::Edge::All, + convertRawProp( + context, + rawProps, + "padding", + sourceValue.padding(yoga::Edge::All), + yogaStyle.padding(yoga::Edge::All))); yogaStyle.setGap( yoga::Gutter::Row, @@ -271,13 +389,86 @@ static inline yoga::Style convertRawProp( sourceValue.gap(yoga::Gutter::All), yogaStyle.gap(yoga::Gutter::All))); - yogaStyle.border() = convertRawProp( - context, - rawProps, - "border", - "Width", - sourceValue.border(), - yogaStyle.border()); + yogaStyle.setBorder( + yoga::Edge::Left, + convertRawProp( + context, + rawProps, + "borderLeftWidth", + sourceValue.border(yoga::Edge::Left), + yogaStyle.border(yoga::Edge::Left))); + + yogaStyle.setBorder( + yoga::Edge::Top, + convertRawProp( + context, + rawProps, + "borderTopWidth", + sourceValue.border(yoga::Edge::Top), + yogaStyle.border(yoga::Edge::Top))); + + yogaStyle.setBorder( + yoga::Edge::Right, + convertRawProp( + context, + rawProps, + "borderRightWidth", + sourceValue.border(yoga::Edge::Right), + yogaStyle.border(yoga::Edge::Right))); + + yogaStyle.setBorder( + yoga::Edge::Bottom, + convertRawProp( + context, + rawProps, + "borderBottomWidth", + sourceValue.border(yoga::Edge::Bottom), + yogaStyle.border(yoga::Edge::Bottom))); + + yogaStyle.setBorder( + yoga::Edge::Start, + convertRawProp( + context, + rawProps, + "borderStartWidth", + sourceValue.border(yoga::Edge::Start), + yogaStyle.border(yoga::Edge::Start))); + + yogaStyle.setBorder( + yoga::Edge::End, + convertRawProp( + context, + rawProps, + "borderEndWidth", + sourceValue.border(yoga::Edge::End), + yogaStyle.border(yoga::Edge::End))); + + yogaStyle.setBorder( + yoga::Edge::Horizontal, + convertRawProp( + context, + rawProps, + "borderHorizontalWidth", + sourceValue.border(yoga::Edge::Horizontal), + yogaStyle.border(yoga::Edge::Horizontal))); + + yogaStyle.setBorder( + yoga::Edge::Vertical, + convertRawProp( + context, + rawProps, + "borderVerticalWidth", + sourceValue.border(yoga::Edge::Vertical), + yogaStyle.border(yoga::Edge::Vertical))); + + yogaStyle.setBorder( + yoga::Edge::All, + convertRawProp( + context, + rawProps, + "borderWidth", + sourceValue.border(yoga::Edge::All), + yogaStyle.border(yoga::Edge::All))); yogaStyle.setDimension( yoga::Dimension::Width, @@ -287,6 +478,7 @@ static inline yoga::Style convertRawProp( "width", sourceValue.dimension(yoga::Dimension::Width), {})); + yogaStyle.setDimension( yoga::Dimension::Height, convertRawProp( @@ -304,6 +496,7 @@ static inline yoga::Style convertRawProp( "minWidth", sourceValue.minDimension(yoga::Dimension::Width), {})); + yogaStyle.setMinDimension( yoga::Dimension::Height, convertRawProp( @@ -321,6 +514,7 @@ static inline yoga::Style convertRawProp( "maxWidth", sourceValue.maxDimension(yoga::Dimension::Width), {})); + yogaStyle.setMaxDimension( yoga::Dimension::Height, convertRawProp( @@ -330,12 +524,12 @@ static inline yoga::Style convertRawProp( sourceValue.maxDimension(yoga::Dimension::Height), {})); - yogaStyle.aspectRatio() = convertRawProp( + yogaStyle.setAspectRatio(convertRawProp( context, rawProps, "aspectRatio", sourceValue.aspectRatio(), - yogaStyle.aspectRatio()); + yogaStyle.aspectRatio())); return yogaStyle; } diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/tests/LayoutTest.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/tests/LayoutTest.cpp index 0e53f62e809bc4..9933cce9f47ed7 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/tests/LayoutTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/tests/LayoutTest.cpp @@ -77,8 +77,8 @@ class LayoutTest : public ::testing::Test { auto &props = *sharedProps; props.layoutConstraints = LayoutConstraints{{0,0}, {500, 500}}; auto &yogaStyle = props.yogaStyle; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(200)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(200)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(200)); return sharedProps; }) .children({ @@ -89,9 +89,9 @@ class LayoutTest : public ::testing::Test { auto sharedProps = std::make_shared(); auto &props = *sharedProps; auto &yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Absolute; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(50)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(50)); + yogaStyle.setPositionType(yoga::PositionType::Absolute); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(50)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(50)); return sharedProps; }) .children({ @@ -102,11 +102,11 @@ class LayoutTest : public ::testing::Test { auto sharedProps = std::make_shared(); auto &props = *sharedProps; auto &yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Absolute; - yogaStyle.position()[YGEdgeLeft] = YGValue{10, YGUnitPoint}; - yogaStyle.position()[YGEdgeTop] = YGValue{10, YGUnitPoint}; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(30)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(90)); + yogaStyle.setPositionType(yoga::PositionType::Absolute); + yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(10)); + yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(10)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(30)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(90)); if (testCase == TRANSFORM_SCALE) { props.transform = props.transform * Transform::Scale(2, 2, 1); @@ -132,14 +132,14 @@ class LayoutTest : public ::testing::Test { auto &yogaStyle = props.yogaStyle; if (testCase == CLIPPING) { - yogaStyle.overflow() = yoga::Overflow::Hidden; + yogaStyle.setOverflow(yoga::Overflow::Hidden); } - yogaStyle.positionType() = yoga::PositionType::Absolute; - yogaStyle.position()[YGEdgeLeft] = YGValue{10, YGUnitPoint}; - yogaStyle.position()[YGEdgeTop] = YGValue{10, YGUnitPoint}; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(110)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(20)); + yogaStyle.setPositionType(yoga::PositionType::Absolute); + yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(10)); + yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(10)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(110)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(20)); return sharedProps; }) .children({ @@ -150,11 +150,11 @@ class LayoutTest : public ::testing::Test { auto sharedProps = std::make_shared(); auto &props = *sharedProps; auto &yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Absolute; - yogaStyle.position()[YGEdgeLeft] = YGValue{70, YGUnitPoint}; - yogaStyle.position()[YGEdgeTop] = YGValue{-50, YGUnitPoint}; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(30)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(60)); + yogaStyle.setPositionType(yoga::PositionType::Absolute); + yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(70)); + yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(-50)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(30)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(60)); return sharedProps; }) }), @@ -165,11 +165,11 @@ class LayoutTest : public ::testing::Test { auto sharedProps = std::make_shared(); auto &props = *sharedProps; auto &yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Absolute; - yogaStyle.position()[YGEdgeLeft] = YGValue{-60, YGUnitPoint}; - yogaStyle.position()[YGEdgeTop] = YGValue{50, YGUnitPoint}; - yogaStyle.setDimension(yoga::Dimension::Width, yoga::CompactValue::of(70)); - yogaStyle.setDimension(yoga::Dimension::Height, yoga::CompactValue::of(20)); + yogaStyle.setPositionType(yoga::PositionType::Absolute); + yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(-60)); + yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(50)); + yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(70)); + yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(20)); return sharedProps; }) }) diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/tests/ViewTest.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/tests/ViewTest.cpp index f948248c680eef..f0302ffc06f9bd 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/tests/ViewTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/tests/ViewTest.cpp @@ -52,8 +52,8 @@ class YogaDirtyFlagTest : public ::testing::Test { auto &props = *mutableViewProps; props.nativeId = "native Id"; props.opacity = 0.5; - props.yogaStyle.alignContent() = yoga::Align::Baseline; - props.yogaStyle.flexDirection() = yoga::FlexDirection::RowReverse; + props.yogaStyle.setAlignContent(yoga::Align::Baseline); + props.yogaStyle.setFlexDirection(yoga::FlexDirection::RowReverse); return mutableViewProps; }), Element() @@ -136,8 +136,8 @@ TEST_F(YogaDirtyFlagTest, changingLayoutSubPropsMustDirtyYogaNode) { auto viewProps = std::make_shared(); auto& props = *viewProps; - props.yogaStyle.alignContent() = yoga::Align::Baseline; - props.yogaStyle.display() = yoga::Display::None; + props.yogaStyle.setAlignContent(yoga::Align::Baseline); + props.yogaStyle.setDisplay(yoga::Display::None); return oldShadowNode.clone(ShadowNodeFragment{viewProps}); }); diff --git a/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h index aa9c40fc8dd5e7..fe4be3a27ba551 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h @@ -8,7 +8,6 @@ #pragma once #include -#include #include #include #include @@ -106,7 +105,7 @@ class ComponentDescriptor { virtual Props::Shared cloneProps( const PropsParserContext& context, const Props::Shared& props, - const RawProps& rawProps) const = 0; + RawProps rawProps) const = 0; /* * Create an initial State object that represents (and contains) an initial @@ -130,12 +129,6 @@ class ComponentDescriptor { virtual ShadowNodeFamily::Shared createFamily( const ShadowNodeFamilyFragment& fragment) const = 0; - /* - * Creates an event emitter for particular node. - */ - virtual SharedEventEmitter createEventEmitter( - const InstanceHandle::Shared& instanceHandle) const = 0; - protected: friend ShadowNode; diff --git a/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h index 4fc25fe73c7776..ad8e60fb541da8 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h @@ -95,7 +95,7 @@ class ConcreteComponentDescriptor : public ComponentDescriptor { virtual Props::Shared cloneProps( const PropsParserContext& context, const Props::Shared& props, - const RawProps& rawProps) const override { + RawProps rawProps) const override { // Optimization: // Quite often nodes are constructed with default/empty props: the base // `props` object is `null` (there no base because it's not cloning) and the @@ -105,7 +105,14 @@ class ConcreteComponentDescriptor : public ComponentDescriptor { return ShadowNodeT::defaultSharedProps(); } - rawProps.parse(rawPropsParser_, context); + if (CoreFeatures::excludeYogaFromRawProps) { + if (ShadowNodeT::IdentifierTrait() == + ShadowNodeTraits::Trait::YogaLayoutableKind) { + rawProps.filterYogaStylePropsInDynamicConversion(); + } + } + + rawProps.parse(rawPropsParser_); // Call old-style constructor auto shadowNodeProps = ShadowNodeT::Props(context, rawProps, props); @@ -155,14 +162,11 @@ class ConcreteComponentDescriptor : public ComponentDescriptor { ShadowNodeFamily::Shared createFamily( const ShadowNodeFamilyFragment& fragment) const override { + auto eventEmitter = std::make_shared( + std::make_shared(fragment.instanceHandle), + eventDispatcher_); return std::make_shared( - fragment, eventDispatcher_, *this); - } - - SharedEventEmitter createEventEmitter( - const InstanceHandle::Shared& instanceHandle) const override { - return std::make_shared( - std::make_shared(instanceHandle), eventDispatcher_); + fragment, std::move(eventEmitter), eventDispatcher_, *this); } protected: diff --git a/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h b/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h index 14c3e9ac481833..ab2ed6cf4da621 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h @@ -70,6 +70,10 @@ class ConcreteShadowNode : public BaseShadowNodeT { return BaseShadowNodeT::BaseTraits(); } + static ShadowNodeTraits::Trait IdentifierTrait() { + return BaseShadowNodeT::IdentifierTrait(); + } + static UnsharedConcreteProps Props( const PropsParserContext& context, const RawProps& rawProps, @@ -81,7 +85,7 @@ class ConcreteShadowNode : public BaseShadowNodeT { rawProps); } - static SharedConcreteProps defaultSharedProps() { + static const SharedConcreteProps& defaultSharedProps() { static const SharedConcreteProps defaultSharedProps = std::make_shared(); return defaultSharedProps; diff --git a/packages/react-native/ReactCommon/react/renderer/core/RawProps.cpp b/packages/react-native/ReactCommon/react/renderer/core/RawProps.cpp index 0739b8ec6b12e9..3e630dcd0d042a 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/RawProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/RawProps.cpp @@ -13,6 +13,96 @@ namespace facebook::react { +namespace { +inline bool isYogaStyleProp(const std::string& prop) { + const static std::unordered_set yogaStylePropNames = { + {"direction", + "flexDirection", + "justifyContent", + "alignContent", + "alignItems", + "alignSelf", + "position", + "flexWrap", + "display", + "flex", + "flexGrow", + "flexShrink", + "flexBasis", + "margin", + "padding", + "rowGap", + "columnGap", + "gap", + // TODO: T163711275 also filter out width/height when SVG no longer read + // them from RawProps + "minWidth", + "maxWidth", + "minHeight", + "maxHeight", + "aspectRatio", + + // edges + "left", + "right", + "top", + "bottom", + "start", + "end", + + // variants of inset + "inset", + "insetStart", + "insetEnd", + "insetInline", + "insetInlineStart", + "insetInlineEnd", + "insetBlock", + "insetBlockEnd", + "insetBlockStart", + "insetVertical", + "insetHorizontal", + "insetTop", + "insetBottom", + "insetLeft", + "insetRight", + + // variants of margin + "marginStart", + "marginEnd", + "marginInline", + "marginInlineStart", + "marginInlineEnd", + "marginBlock", + "marginBlockStart", + "marginBlockEnd", + "marginVertical", + "marginHorizontal", + "marginTop", + "marginBottom", + "marginLeft", + "marginRight", + + // variants of padding + "paddingStart", + "paddingEnd", + "paddingInline", + "paddingInlineStart", + "paddingInlineEnd", + "paddingBlock", + "paddingBlockStart", + "paddingBlockEnd", + "paddingVertical", + "paddingHorizontal", + "paddingTop", + "paddingBottom", + "paddingLeft", + "paddingRight"}}; + + return yogaStylePropNames.find(prop) != yogaStylePropNames.end(); +} +} // namespace + RawProps::RawProps() { mode_ = Mode::Empty; } @@ -26,7 +116,7 @@ RawProps::RawProps(jsi::Runtime& runtime, const jsi::Value& value) noexcept { return; } - mode_ = mode_ = Mode::JSI; + mode_ = Mode::JSI; runtime_ = &runtime; value_ = jsi::Value(runtime, value); } @@ -47,9 +137,30 @@ RawProps::RawProps(folly::dynamic dynamic) noexcept { dynamic_ = std::move(dynamic); } -void RawProps::parse( - const RawPropsParser& parser, - const PropsParserContext& /*unused*/) const noexcept { +RawProps::RawProps(const RawProps& other) noexcept { + mode_ = other.mode_; + if (mode_ == Mode::JSI) { + runtime_ = other.runtime_; + value_ = jsi::Value(*runtime_, other.value_); + } else if (mode_ == Mode::Dynamic) { + dynamic_ = other.dynamic_; + } + ignoreYogaStyleProps_ = other.ignoreYogaStyleProps_; +} + +RawProps& RawProps::operator=(const RawProps& other) noexcept { + mode_ = other.mode_; + if (mode_ == Mode::JSI) { + runtime_ = other.runtime_; + value_ = jsi::Value(*runtime_, other.value_); + } else if (mode_ == Mode::Dynamic) { + dynamic_ = other.dynamic_; + } + ignoreYogaStyleProps_ = other.ignoreYogaStyleProps_; + return *this; +} + +void RawProps::parse(const RawPropsParser& parser) noexcept { react_native_assert(parser_ == nullptr && "A parser was already assigned."); parser_ = &parser; parser.preparse(*this); @@ -65,12 +176,17 @@ RawProps::operator folly::dynamic() const noexcept { case Mode::Empty: return folly::dynamic::object(); case Mode::JSI: - return jsi::dynamicFromValue(*runtime_, value_); + return jsi::dynamicFromValue( + *runtime_, value_, ignoreYogaStyleProps_ ? isYogaStyleProp : nullptr); case Mode::Dynamic: return dynamic_; } } +void RawProps::filterYogaStylePropsInDynamicConversion() noexcept { + ignoreYogaStyleProps_ = true; +} + /* * Returns `true` if the object is empty. * Empty `RawProps` does not have any stored data. diff --git a/packages/react-native/ReactCommon/react/renderer/core/RawProps.h b/packages/react-native/ReactCommon/react/renderer/core/RawProps.h index e01af9f84db306..7edaa8a7ed30f0 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/RawProps.h +++ b/packages/react-native/ReactCommon/react/renderer/core/RawProps.h @@ -50,6 +50,12 @@ class RawProps final { */ RawProps(jsi::Runtime& runtime, const jsi::Value& value) noexcept; + explicit RawProps(const RawProps& rawProps) noexcept; + RawProps& operator=(const RawProps& other) noexcept; + + RawProps(RawProps&& other) noexcept = default; + RawProps& operator=(RawProps&& other) noexcept = default; + /* * Creates an object with given `folly::dynamic` object. * Deprecated. Do not use. @@ -58,20 +64,7 @@ class RawProps final { */ explicit RawProps(folly::dynamic dynamic) noexcept; - /* - * Not moveable. - */ - RawProps(RawProps&& other) noexcept = delete; - RawProps& operator=(RawProps&& other) noexcept = delete; - - /* - * Not copyable. - */ - RawProps(const RawProps& other) noexcept = delete; - RawProps& operator=(const RawProps& other) noexcept = delete; - - void parse(const RawPropsParser& parser, const PropsParserContext&) - const noexcept; + void parse(const RawPropsParser& parser) noexcept; /* * Deprecated. Do not use. @@ -80,6 +73,15 @@ class RawProps final { */ explicit operator folly::dynamic() const noexcept; + /* + * Once called, Yoga style props will be filtered out during conversion to + * folly::dynamic. folly::dynamic conversion is only used on Android and props + * specific to Yoga do not need to be send over JNI to Android. + * This is a performance optimisation to minimise traffic between C++ and + * Java. + */ + void filterYogaStylePropsInDynamicConversion() noexcept; + /* * Returns `true` if the object is empty. * Empty `RawProps` does not have any stored data. @@ -131,6 +133,8 @@ class RawProps final { */ mutable std::vector keyIndexToValueIndex_; mutable std::vector values_; + + bool ignoreYogaStyleProps_{false}; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/RawPropsParser.h b/packages/react-native/ReactCommon/react/renderer/core/RawPropsParser.h index 5150189817134d..de0b1c7fcfabcc 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/RawPropsParser.h +++ b/packages/react-native/ReactCommon/react/renderer/core/RawPropsParser.h @@ -46,7 +46,7 @@ class RawPropsParser final { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - emptyRawProps.parse(*this, parserContext); + emptyRawProps.parse(*this); PropsT(parserContext, {}, emptyRawProps); postPrepare(); } diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h index 74f08707b12c48..630082ce698692 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h @@ -59,6 +59,10 @@ class ShadowNode : public Sealable, return ShadowNodeTraits{}; } + static ShadowNodeTraits::Trait IdentifierTrait() { + return ShadowNodeTraits::Trait::None; + } + #pragma mark - Constructors /* diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.cpp b/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.cpp index cf2bd385b95c5f..0e73b0a5cf3687 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.cpp @@ -20,14 +20,14 @@ using AncestorList = ShadowNode::AncestorList; ShadowNodeFamily::ShadowNodeFamily( const ShadowNodeFamilyFragment& fragment, + SharedEventEmitter eventEmitter, EventDispatcher::Weak eventDispatcher, const ComponentDescriptor& componentDescriptor) : eventDispatcher_(std::move(eventDispatcher)), tag_(fragment.tag), surfaceId_(fragment.surfaceId), instanceHandle_(fragment.instanceHandle), - eventEmitter_( - componentDescriptor.createEventEmitter(fragment.instanceHandle)), + eventEmitter_(std::move(eventEmitter)), componentDescriptor_(componentDescriptor), componentHandle_(componentDescriptor.getComponentHandle()), componentName_(componentDescriptor.getComponentName()) {} diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.h b/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.h index 1fefb9532eae45..dc5dbc815317f0 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNodeFamily.h @@ -50,6 +50,7 @@ class ShadowNodeFamily final { ShadowNodeFamily( const ShadowNodeFamilyFragment& fragment, + SharedEventEmitter eventEmitter, EventDispatcher::Weak eventDispatcher, const ComponentDescriptor& componentDescriptor); diff --git a/packages/react-native/ReactCommon/react/renderer/core/tests/ComponentDescriptorTest.cpp b/packages/react-native/ReactCommon/react/renderer/core/tests/ComponentDescriptorTest.cpp index d9d623713d4ef6..1b29638cc019ba 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/tests/ComponentDescriptorTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/tests/ComponentDescriptorTest.cpp @@ -26,8 +26,9 @@ TEST(ComponentDescriptorTest, createShadowNode) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps(folly::dynamic::object("nativeID", "abc")); - Props::Shared props = descriptor->cloneProps(parserContext, nullptr, raw); + auto rawProps = RawProps(folly::dynamic::object("nativeID", "abc")); + Props::Shared props = + descriptor->cloneProps(parserContext, nullptr, std::move(rawProps)); auto family = descriptor->createFamily(ShadowNodeFamilyFragment{ /* .tag = */ 9, @@ -58,8 +59,9 @@ TEST(ComponentDescriptorTest, cloneShadowNode) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps(folly::dynamic::object("nativeID", "abc")); - Props::Shared props = descriptor->cloneProps(parserContext, nullptr, raw); + auto rawProps = RawProps(folly::dynamic::object("nativeID", "abc")); + Props::Shared props = + descriptor->cloneProps(parserContext, nullptr, std::move(rawProps)); auto family = descriptor->createFamily(ShadowNodeFamilyFragment{ /* .tag = */ 9, /* .surfaceId = */ 1, @@ -91,8 +93,9 @@ TEST(ComponentDescriptorTest, appendChild) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps(folly::dynamic::object("nativeID", "abc")); - Props::Shared props = descriptor->cloneProps(parserContext, nullptr, raw); + auto rawProps = RawProps(folly::dynamic::object("nativeID", "abc")); + Props::Shared props = + descriptor->cloneProps(parserContext, nullptr, std::move(rawProps)); auto family1 = descriptor->createFamily(ShadowNodeFamilyFragment{ /* .tag = */ 1, /* .surfaceId = */ 1, diff --git a/packages/react-native/ReactCommon/react/renderer/core/tests/EventTargetTests.cpp b/packages/react-native/ReactCommon/react/renderer/core/tests/EventTargetTests.cpp new file mode 100644 index 00000000000000..2f919870c795a3 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/core/tests/EventTargetTests.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +using namespace facebook; +using namespace facebook::react; + +TEST(EventTargetTests, getInstanceHandle) { + auto runtime = facebook::hermes::makeHermesRuntime(); + auto object = jsi::Object(*runtime); + auto instanceHandle = std::make_shared( + *runtime, jsi::Value(*runtime, object), 1); + + EXPECT_EQ(instanceHandle->getTag(), 1); + + auto eventTarget = EventTarget(std::move(instanceHandle)); + + EXPECT_EQ(eventTarget.getTag(), 1); + + EXPECT_TRUE(eventTarget.getInstanceHandle(*runtime).isNull()); + + eventTarget.retain(*runtime); + + EXPECT_TRUE(eventTarget.getInstanceHandle(*runtime).isNull()); + + eventTarget.setEnabled(true); + + eventTarget.retain(*runtime); + + EXPECT_FALSE(eventTarget.getInstanceHandle(*runtime).isNull()); + + eventTarget.release(*runtime); + + EXPECT_TRUE(eventTarget.getInstanceHandle(*runtime).isNull()); +} diff --git a/packages/react-native/ReactCommon/react/renderer/core/tests/FindNodeAtPointTest.cpp b/packages/react-native/ReactCommon/react/renderer/core/tests/FindNodeAtPointTest.cpp index 25bc0e35d4768a..c5f74fd84fb94c 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/tests/FindNodeAtPointTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/tests/FindNodeAtPointTest.cpp @@ -202,7 +202,7 @@ TEST(FindNodeAtPointTest, overlappingViewsWithZIndex) { auto sharedProps = std::make_shared(); sharedProps->zIndex = 1; auto &yogaStyle = sharedProps->yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Absolute; + yogaStyle.setPositionType(yoga::PositionType::Absolute); return sharedProps; }) .finalize([](ViewShadowNode &shadowNode){ diff --git a/packages/react-native/ReactCommon/react/renderer/core/tests/RawPropsTest.cpp b/packages/react-native/ReactCommon/react/renderer/core/tests/RawPropsTest.cpp index bca6d019ffbbd0..ea9e657a428791 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/tests/RawPropsTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/tests/RawPropsTest.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #include "TestComponent.h" +using namespace facebook; using namespace facebook::react; class PropsSingleFloat : public Props { @@ -151,10 +153,10 @@ TEST(RawPropsTest, handleProps) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps(folly::dynamic::object("nativeID", "abc")); + auto raw = RawProps(folly::dynamic::object("nativeID", "abc")); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); auto props = std::make_shared(parserContext, Props(), raw); @@ -168,10 +170,10 @@ TEST(RawPropsTest, handleRawPropsSingleString) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps(folly::dynamic::object("nativeID", "abc")); + auto raw = RawProps(folly::dynamic::object("nativeID", "abc")); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); std::string value = (std::string)*raw.at("nativeID", nullptr, nullptr); @@ -182,11 +184,10 @@ TEST(RawPropsTest, handleRawPropsSingleFloat) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = - RawProps(folly::dynamic::object("floatValue", (float)42.42)); + auto raw = RawProps(folly::dynamic::object("floatValue", (float)42.42)); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); auto value = (float)*raw.at("floatValue", nullptr, nullptr); @@ -197,11 +198,10 @@ TEST(RawPropsTest, handleRawPropsSingleDouble) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = - RawProps(folly::dynamic::object("doubleValue", (double)42.42)); + auto raw = RawProps(folly::dynamic::object("doubleValue", (double)42.42)); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); auto value = (double)*raw.at("doubleValue", nullptr, nullptr); @@ -212,10 +212,10 @@ TEST(RawPropsTest, handleRawPropsSingleInt) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps(folly::dynamic::object("intValue", (int)42.42)); + auto raw = RawProps(folly::dynamic::object("intValue", (int)42.42)); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); int value = (int)*raw.at("intValue", nullptr, nullptr); @@ -226,10 +226,10 @@ TEST(RawPropsTest, handleRawPropsSingleIntGetManyTimes) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps(folly::dynamic::object("intValue", (int)42.42)); + auto raw = RawProps(folly::dynamic::object("intValue", (int)42.42)); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); @@ -240,14 +240,14 @@ TEST(RawPropsTest, handleRawPropsPrimitiveTypes) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps( + auto raw = RawProps( folly::dynamic::object("intValue", (int)42)("doubleValue", (double)17.42)( "floatValue", (float)66.67)("stringValue", "helloworld")("boolValue", true)); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_NEAR((double)*raw.at("doubleValue", nullptr, nullptr), 17.42, 0.0001); @@ -262,14 +262,14 @@ TEST(RawPropsTest, handleRawPropsPrimitiveTypesGetTwice) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps( + auto raw = RawProps( folly::dynamic::object("intValue", (int)42)("doubleValue", (double)17.42)( "floatValue", (float)66.67)("stringValue", "helloworld")("boolValue", true)); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_NEAR((double)*raw.at("doubleValue", nullptr, nullptr), 17.42, 0.0001); @@ -292,14 +292,14 @@ TEST(RawPropsTest, handleRawPropsPrimitiveTypesGetOutOfOrder) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps( + auto raw = RawProps( folly::dynamic::object("intValue", (int)42)("doubleValue", (double)17.42)( "floatValue", (float)66.67)("stringValue", "helloworld")("boolValue", true)); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_NEAR((double)*raw.at("doubleValue", nullptr, nullptr), 17.42, 0.0001); @@ -322,11 +322,11 @@ TEST(RawPropsTest, handleRawPropsPrimitiveTypesIncomplete) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps(folly::dynamic::object("intValue", (int)42)); + auto raw = RawProps(folly::dynamic::object("intValue", (int)42)); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); EXPECT_EQ((int)*raw.at("intValue", nullptr, nullptr), 42); EXPECT_EQ(raw.at("doubleValue", nullptr, nullptr), nullptr); @@ -342,11 +342,11 @@ TEST(RawPropsTest, handleRawPropsPrimitiveTypesIncorrectLookup) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps(folly::dynamic::object("intValue", (int)42)); + auto raw = RawProps(folly::dynamic::object("intValue", (int)42)); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); // Before D18662135, looking up an invalid key would trigger // an infinite loop. This is out of contract, so we should only @@ -360,10 +360,10 @@ TEST(RawPropsTest, handlePropsMultiLookup) { ContextContainer contextContainer{}; PropsParserContext parserContext{-1, contextContainer}; - const auto& raw = RawProps(folly::dynamic::object("floatValue", (float)10.0)); + auto raw = RawProps(folly::dynamic::object("floatValue", (float)10.0)); auto parser = RawPropsParser(); parser.prepare(); - raw.parse(parser, parserContext); + raw.parse(parser); auto props = std::make_shared( parserContext, PropsMultiLookup(), raw); @@ -374,3 +374,132 @@ TEST(RawPropsTest, handlePropsMultiLookup) { EXPECT_NEAR(props->floatValue, 10.0, 0.00001); EXPECT_NEAR(props->derivedFloatValue, 20.0, 0.00001); } + +TEST(RawPropsTest, copyDynamicRawProps) { + ContextContainer contextContainer{}; + PropsParserContext parserContext{-1, contextContainer}; + + auto rawProps = RawProps(folly::dynamic::object("floatValue", (float)10.0)); + + auto copy = RawProps(rawProps); + + EXPECT_FALSE(copy.isEmpty()); + + auto parser = RawPropsParser(); + parser.prepare(); + + rawProps.parse(parser); + copy.parse(parser); + + auto originalProps = std::make_shared( + parserContext, PropsMultiLookup(), rawProps); + auto copyProps = std::make_shared( + parserContext, PropsMultiLookup(), copy); + + // Props are not sealed after applying raw props. + EXPECT_FALSE(copyProps->getSealed()); + + EXPECT_NEAR(copyProps->floatValue, originalProps->floatValue, 0.00001); + EXPECT_NEAR( + copyProps->derivedFloatValue, originalProps->derivedFloatValue, 0.00001); +} + +TEST(RawPropsTest, copyEmptyRawProps) { + ContextContainer contextContainer{}; + PropsParserContext parserContext{-1, contextContainer}; + + auto rawProps = RawProps(); + + auto copy = RawProps(rawProps); + + EXPECT_TRUE(rawProps.isEmpty()); + EXPECT_TRUE(copy.isEmpty()); + + EXPECT_TRUE(((folly::dynamic)copy).empty()); +} + +TEST(RawPropsTest, copyNullJSIRawProps) { + auto runtime = facebook::hermes::makeHermesRuntime(); + + ContextContainer contextContainer{}; + PropsParserContext parserContext{-1, contextContainer}; + + auto rawProps = RawProps(*runtime, jsi::Value::null()); + + auto copy = RawProps(rawProps); + + EXPECT_TRUE(rawProps.isEmpty()); + EXPECT_TRUE(copy.isEmpty()); + + EXPECT_TRUE(((folly::dynamic)copy).empty()); +} + +TEST(RawPropsTest, copyJSIRawProps) { + auto runtime = facebook::hermes::makeHermesRuntime(); + + ContextContainer contextContainer{}; + PropsParserContext parserContext{-1, contextContainer}; + + auto object = jsi::Object(*runtime); + object.setProperty(*runtime, "floatValue", 10.0); + + auto rawProps = RawProps(*runtime, jsi::Value(*runtime, object)); + auto copy = RawProps(rawProps); + + EXPECT_FALSE(rawProps.isEmpty()); + EXPECT_FALSE(copy.isEmpty()); + + auto parser = RawPropsParser(); + parser.prepare(); + + rawProps.parse(parser); + copy.parse(parser); + + auto originalProps = std::make_shared( + parserContext, PropsMultiLookup(), rawProps); + auto copyProps = std::make_shared( + parserContext, PropsMultiLookup(), copy); + + // Props are not sealed after applying raw props. + EXPECT_FALSE(copyProps->getSealed()); + + EXPECT_NEAR(copyProps->floatValue, originalProps->floatValue, 0.00001); + EXPECT_NEAR( + copyProps->derivedFloatValue, originalProps->derivedFloatValue, 0.00001); +} + +TEST(RawPropsTest, filterYogaRawProps) { + auto runtime = facebook::hermes::makeHermesRuntime(); + + ContextContainer contextContainer{}; + PropsParserContext parserContext{-1, contextContainer}; + + auto object = jsi::Object(*runtime); + object.setProperty(*runtime, "floatValue", 10.0); + object.setProperty(*runtime, "flex", 1); + + auto rawProps = RawProps(*runtime, jsi::Value(*runtime, object)); + + EXPECT_FALSE(rawProps.isEmpty()); + + auto dynamicProps = (folly::dynamic)rawProps; + + EXPECT_EQ(dynamicProps["floatValue"], 10.0); + EXPECT_EQ(dynamicProps["flex"], 1); + + rawProps.filterYogaStylePropsInDynamicConversion(); + + dynamicProps = (folly::dynamic)rawProps; + + EXPECT_EQ(dynamicProps["floatValue"], 10.0); + EXPECT_EQ(dynamicProps["flex"], nullptr); + + // The fact that filterYogaStylePropsInDynamicConversion should + // must apply to a copy as well. + auto copy = RawProps(rawProps); + + auto dynamicPropsFromCopy = (folly::dynamic)copy; + + EXPECT_EQ(dynamicPropsFromCopy["floatValue"], 10.0); + EXPECT_EQ(dynamicPropsFromCopy["flex"], nullptr); +} diff --git a/packages/react-native/ReactCommon/react/renderer/core/tests/ShadowNodeTest.cpp b/packages/react-native/ReactCommon/react/renderer/core/tests/ShadowNodeTest.cpp index 8a1f19bdd8a894..ac00541f1030f4 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/tests/ShadowNodeTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/tests/ShadowNodeTest.cpp @@ -37,14 +37,11 @@ class ShadowNodeTest : public ::testing::Test { auto traits = TestShadowNode::BaseTraits(); - auto familyAA = std::make_shared( - ShadowNodeFamilyFragment{ - /* .tag = */ 11, - /* .surfaceId = */ surfaceId_, - /* .instanceHandle = */ nullptr, - }, - eventDispatcher_, - componentDescriptor_); + auto familyAA = componentDescriptor_.createFamily(ShadowNodeFamilyFragment{ + /* .tag = */ 11, + /* .surfaceId = */ surfaceId_, + /* .instanceHandle = */ nullptr, + }); nodeAA_ = std::make_shared( ShadowNodeFragment{ /* .props = */ props, @@ -53,14 +50,11 @@ class ShadowNodeTest : public ::testing::Test { familyAA, traits); - auto familyABA = std::make_shared( - ShadowNodeFamilyFragment{ - /* .tag = */ 12, - /* .surfaceId = */ surfaceId_, - /* .instanceHandle = */ nullptr, - }, - eventDispatcher_, - componentDescriptor_); + auto familyABA = componentDescriptor_.createFamily(ShadowNodeFamilyFragment{ + /* .tag = */ 12, + /* .surfaceId = */ surfaceId_, + /* .instanceHandle = */ nullptr, + }); nodeABA_ = std::make_shared( ShadowNodeFragment{ /* .props = */ props, @@ -69,14 +63,11 @@ class ShadowNodeTest : public ::testing::Test { familyABA, traits); - auto familyABB = std::make_shared( - ShadowNodeFamilyFragment{ - /* .tag = */ 13, - /* .surfaceId = */ surfaceId_, - /* .instanceHandle = */ nullptr, - }, - eventDispatcher_, - componentDescriptor_); + auto familyABB = componentDescriptor_.createFamily(ShadowNodeFamilyFragment{ + /* .tag = */ 13, + /* .surfaceId = */ surfaceId_, + /* .instanceHandle = */ nullptr, + }); nodeABB_ = std::make_shared( ShadowNodeFragment{ /* .props = */ props, @@ -88,14 +79,11 @@ class ShadowNodeTest : public ::testing::Test { auto nodeABChildren = std::make_shared( ShadowNode::ListOfShared{nodeABA_, nodeABB_}); - auto familyAB = std::make_shared( - ShadowNodeFamilyFragment{ - /* .tag = */ 15, - /* .surfaceId = */ surfaceId_, - /* .instanceHandle = */ nullptr, - }, - eventDispatcher_, - componentDescriptor_); + auto familyAB = componentDescriptor_.createFamily(ShadowNodeFamilyFragment{ + /* .tag = */ 15, + /* .surfaceId = */ surfaceId_, + /* .instanceHandle = */ nullptr, + }); nodeAB_ = std::make_shared( ShadowNodeFragment{ /* .props = */ props, @@ -104,14 +92,11 @@ class ShadowNodeTest : public ::testing::Test { familyAB, traits); - auto familyAC = std::make_shared( - ShadowNodeFamilyFragment{ - /* .tag = */ 16, - /* .surfaceId = */ surfaceId_, - /* .instanceHandle = */ nullptr, - }, - eventDispatcher_, - componentDescriptor_); + auto familyAC = componentDescriptor_.createFamily(ShadowNodeFamilyFragment{ + /* .tag = */ 16, + /* .surfaceId = */ surfaceId_, + /* .instanceHandle = */ nullptr, + }); nodeAC_ = std::make_shared( ShadowNodeFragment{ /* .props = */ props, @@ -123,14 +108,11 @@ class ShadowNodeTest : public ::testing::Test { auto nodeAChildren = std::make_shared( ShadowNode::ListOfShared{nodeAA_, nodeAB_, nodeAC_}); - auto familyA = std::make_shared( - ShadowNodeFamilyFragment{ - /* .tag = */ 17, - /* .surfaceId = */ surfaceId_, - /* .instanceHandle = */ nullptr, - }, - eventDispatcher_, - componentDescriptor_); + auto familyA = componentDescriptor_.createFamily(ShadowNodeFamilyFragment{ + /* .tag = */ 17, + /* .surfaceId = */ surfaceId_, + /* .instanceHandle = */ nullptr, + }); nodeA_ = std::make_shared( ShadowNodeFragment{ /* .props = */ props, @@ -139,14 +121,11 @@ class ShadowNodeTest : public ::testing::Test { familyA, traits); - auto familyZ = std::make_shared( - ShadowNodeFamilyFragment{ - /* .tag = */ 18, - /* .surfaceId = */ surfaceId_, - /* .instanceHandle = */ nullptr, - }, - eventDispatcher_, - componentDescriptor_); + auto familyZ = componentDescriptor_.createFamily(ShadowNodeFamilyFragment{ + /* .tag = */ 18, + /* .surfaceId = */ surfaceId_, + /* .instanceHandle = */ nullptr, + }); nodeZ_ = std::make_shared( ShadowNodeFragment{ /* .props = */ props, @@ -234,14 +213,11 @@ TEST_F(ShadowNodeTest, handleCloneFunction) { } TEST_F(ShadowNodeTest, handleState) { - auto family = std::make_shared( - ShadowNodeFamilyFragment{ - /* .tag = */ 9, - /* .surfaceId = */ surfaceId_, - /* .instanceHandle = */ nullptr, - }, - eventDispatcher_, - componentDescriptor_); + auto family = componentDescriptor_.createFamily(ShadowNodeFamilyFragment{ + /* .tag = */ 9, + /* .surfaceId = */ surfaceId_, + /* .instanceHandle = */ nullptr, + }); auto traits = TestShadowNode::BaseTraits(); diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageManager.h b/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageManager.h index 600e4b3d99138b..128be69838884a 100644 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageManager.h +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageManager.h @@ -21,15 +21,17 @@ class ImageManager; using SharedImageManager = std::shared_ptr; /* - * Cross platform facade for iOS-specific RCTImageManager. + * Cross platform facade for image management (e.g. iOS-specific + * RCTImageManager) */ class ImageManager { public: ImageManager(const ContextContainer::Shared& contextContainer); - ~ImageManager(); + virtual ~ImageManager(); - ImageRequest requestImage(const ImageSource& imageSource, SurfaceId surfaceId) - const; + virtual ImageRequest requestImage( + const ImageSource& imageSource, + SurfaceId surfaceId) const; private: void* self_{}; diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequest.cpp b/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageRequest.cpp similarity index 100% rename from packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequest.cpp rename to packages/react-native/ReactCommon/react/renderer/imagemanager/ImageRequest.cpp diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequest.cpp b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequest.cpp deleted file mode 100644 index 7974e06a2c1b9e..00000000000000 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequest.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "ImageRequest.h" - -#include - -namespace facebook::react { - -ImageRequest::ImageRequest( - ImageSource imageSource, - std::shared_ptr telemetry, - SharedFunction<> cancelationFunction) - : imageSource_(std::move(imageSource)), - telemetry_(std::move(telemetry)), - cancelRequest_(std::move(cancelationFunction)) { - // Not implemented. -} - -const ImageResponseObserverCoordinator& ImageRequest::getObserverCoordinator() - const { - // Not implemented - abort(); -} - -const std::shared_ptr& -ImageRequest::getSharedObserverCoordinator() const { - // Not implemented - abort(); -} - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/React-ImageManager.podspec b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/React-ImageManager.podspec index c85d5511f62df3..6feeafaf718f0d 100644 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/React-ImageManager.podspec +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/React-ImageManager.podspec @@ -56,7 +56,6 @@ Pod::Spec.new do |s| s.dependency "RCT-Folly/Fabric" s.dependency "React-Core/Default" - s.dependency "React-RCTImage" s.dependency "glog" add_dependency(s, "React-Fabric") diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp b/packages/react-native/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp index 262e7e10c2f541..e1eabecd057ad2 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp @@ -251,9 +251,9 @@ TEST_F(StackingContextTest, mostPropsDoNotForceViewsToMaterialize) { mutateViewShadowNodeProps_(nodeAA_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.padding()[YGEdgeAll] = YGValue{42, YGUnitPoint}; - yogaStyle.margin()[YGEdgeAll] = YGValue{42, YGUnitPoint}; - yogaStyle.positionType() = yoga::PositionType::Absolute; + yogaStyle.setPadding(yoga::Edge::All, yoga::value::points(42)); + yogaStyle.setMargin(yoga::Edge::All, yoga::value::points(42)); + yogaStyle.setPositionType(yoga::PositionType::Absolute); props.shadowRadius = 42; props.shadowOffset = Size{42, 42}; props.backgroundColor = clearColor(); @@ -262,14 +262,14 @@ TEST_F(StackingContextTest, mostPropsDoNotForceViewsToMaterialize) { mutateViewShadowNodeProps_(nodeBA_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; props.zIndex = 42; - yogaStyle.margin()[YGEdgeAll] = YGValue{42, YGUnitPoint}; + yogaStyle.setMargin(yoga::Edge::All, yoga::value::points(42)); props.shadowColor = clearColor(); props.shadowOpacity = 0.42; }); mutateViewShadowNodeProps_(nodeBBA_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Relative; + yogaStyle.setPositionType(yoga::PositionType::Relative); props.borderRadii.all = 42; props.borderColors.all = blackColor(); @@ -456,7 +456,7 @@ TEST_F(StackingContextTest, somePropsForceViewsToMaterialize2) { mutateViewShadowNodeProps_(nodeBBB_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Relative; + yogaStyle.setPositionType(yoga::PositionType::Relative); props.zIndex = 42; }); @@ -538,37 +538,37 @@ TEST_F(StackingContextTest, zIndexAndFlattenedNodes) { mutateViewShadowNodeProps_(nodeAA_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Relative; + yogaStyle.setPositionType(yoga::PositionType::Relative); props.zIndex = 9001; }); mutateViewShadowNodeProps_(nodeBA_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Relative; + yogaStyle.setPositionType(yoga::PositionType::Relative); props.zIndex = 9000; }); mutateViewShadowNodeProps_(nodeBBA_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Relative; + yogaStyle.setPositionType(yoga::PositionType::Relative); props.zIndex = 8999; }); mutateViewShadowNodeProps_(nodeBBB_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Relative; + yogaStyle.setPositionType(yoga::PositionType::Relative); props.zIndex = 8998; }); mutateViewShadowNodeProps_(nodeBC_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Relative; + yogaStyle.setPositionType(yoga::PositionType::Relative); props.zIndex = 8997; }); mutateViewShadowNodeProps_(nodeBD_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Relative; + yogaStyle.setPositionType(yoga::PositionType::Relative); props.zIndex = 8996; }); @@ -652,7 +652,7 @@ TEST_F(StackingContextTest, zIndexAndFlattenedNodes) { mutateViewShadowNodeProps_(nodeBB_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Relative; + yogaStyle.setPositionType(yoga::PositionType::Relative); props.zIndex = 42; }); @@ -680,7 +680,7 @@ TEST_F(StackingContextTest, zIndexAndFlattenedNodes) { mutateViewShadowNodeProps_(nodeBB_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.positionType() = yoga::PositionType::Static; + yogaStyle.setPositionType(yoga::PositionType::Static); props.zIndex = {}; }); @@ -764,7 +764,7 @@ TEST_F(StackingContextTest, zIndexAndFlattenedNodes) { mutateViewShadowNodeProps_(nodeBB_, [](ViewProps& props) { auto& yogaStyle = props.yogaStyle; - yogaStyle.display() = yoga::Display::None; + yogaStyle.setDisplay(yoga::Display::None); }); testViewTree_([](const StubViewTree& viewTree) { diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp index 0dd12526bc730e..a0f667430a912f 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp @@ -66,7 +66,7 @@ std::shared_ptr UIManager::createNode( Tag tag, const std::string& name, SurfaceId surfaceId, - const RawProps& rawProps, + RawProps rawProps, InstanceHandle::Shared instanceHandle) const { SystraceSection s("UIManager::createNode", "componentName", name); @@ -78,8 +78,8 @@ std::shared_ptr UIManager::createNode( auto family = componentDescriptor.createFamily( {tag, surfaceId, std::move(instanceHandle)}); - const auto props = - componentDescriptor.cloneProps(propsParserContext, nullptr, rawProps); + const auto props = componentDescriptor.cloneProps( + propsParserContext, nullptr, std::move(rawProps)); const auto state = componentDescriptor.createInitialState(props, family); auto shadowNode = componentDescriptor.createShadowNode( @@ -111,7 +111,7 @@ std::shared_ptr UIManager::createNode( std::shared_ptr UIManager::cloneNode( const ShadowNode& shadowNode, const ShadowNode::SharedListOfShared& children, - const RawProps* rawProps) const { + RawProps rawProps) const { SystraceSection s( "UIManager::cloneNode", "componentName", shadowNode.getComponentName()); @@ -122,7 +122,7 @@ std::shared_ptr UIManager::cloneNode( auto& family = shadowNode.getFamily(); auto props = ShadowNodeFragment::propsPlaceholder(); - if (rawProps != nullptr) { + if (!rawProps.isEmpty()) { if (family.nativeProps_DEPRECATED != nullptr) { // Values in `rawProps` patch (take precedence over) // `nativeProps_DEPRECATED`. For example, if both `nativeProps_DEPRECATED` @@ -130,7 +130,7 @@ std::shared_ptr UIManager::cloneNode( // was previously in `nativeProps_DEPRECATED`. family.nativeProps_DEPRECATED = std::make_unique(mergeDynamicProps( - *family.nativeProps_DEPRECATED, (folly::dynamic)*rawProps)); + *family.nativeProps_DEPRECATED, (folly::dynamic)rawProps)); props = componentDescriptor.cloneProps( propsParserContext, @@ -138,7 +138,7 @@ std::shared_ptr UIManager::cloneNode( RawProps(*family.nativeProps_DEPRECATED)); } else { props = componentDescriptor.cloneProps( - propsParserContext, shadowNode.getProps(), *rawProps); + propsParserContext, shadowNode.getProps(), std::move(rawProps)); } } @@ -457,7 +457,7 @@ void UIManager::dispatchCommand( void UIManager::setNativeProps_DEPRECATED( const ShadowNode::Shared& shadowNode, - const RawProps& rawProps) const { + RawProps rawProps) const { auto& family = shadowNode->getFamily(); if (family.nativeProps_DEPRECATED) { // Values in `rawProps` patch (take precedence over) @@ -474,6 +474,8 @@ void UIManager::setNativeProps_DEPRECATED( shadowTreeRegistry_.visit( family.getSurfaceId(), [&](const ShadowTree& shadowTree) { + // The lambda passed to `commit` may be executed multiple times. + // We need to create fresh copy of the `RawProps` object each time. shadowTree.commit( [&](RootShadowNode const& oldRootShadowNode) { auto rootNode = oldRootShadowNode.cloneTree( @@ -486,7 +488,7 @@ void UIManager::setNativeProps_DEPRECATED( auto props = componentDescriptor.cloneProps( propsParserContext, getNewestCloneOfShadowNode(*shadowNode)->getProps(), - rawProps); + RawProps(rawProps)); return oldShadowNode.clone({/* .props = */ props}); }); diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h index 7ea9b28dcdff9b..e63941b24b3205 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h @@ -134,13 +134,13 @@ class UIManager final : public ShadowTreeDelegate { Tag tag, const std::string& componentName, SurfaceId surfaceId, - const RawProps& props, + RawProps props, InstanceHandle::Shared instanceHandle) const; std::shared_ptr cloneNode( const ShadowNode& shadowNode, - const ShadowNode::SharedListOfShared& children = nullptr, - const RawProps* rawProps = nullptr) const; + const ShadowNode::SharedListOfShared& children, + RawProps rawProps) const; void appendChild( const ShadowNode::Shared& parentShadowNode, @@ -183,7 +183,7 @@ class UIManager final : public ShadowTreeDelegate { void setNativeProps_DEPRECATED( const ShadowNode::Shared& shadowNode, - const RawProps& rawProps) const; + RawProps rawProps) const; void sendAccessibilityEvent( const ShadowNode::Shared& shadowNode, diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp index 9813ea84ccc51f..739729f2d8fe6b 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp @@ -230,23 +230,27 @@ jsi::Value UIManagerBinding::get( const jsi::Value& /*thisValue*/, const jsi::Value* arguments, size_t count) -> jsi::Value { - validateArgumentCount(runtime, methodName, paramCount, count); - - auto instanceHandle = - instanceHandleFromValue(runtime, arguments[4], arguments[0]); - if (!instanceHandle) { - react_native_assert(false); - return jsi::Value::undefined(); + try { + validateArgumentCount(runtime, methodName, paramCount, count); + + auto instanceHandle = + instanceHandleFromValue(runtime, arguments[4], arguments[0]); + if (!instanceHandle) { + react_native_assert(false); + return jsi::Value::undefined(); + } + + return valueFromShadowNode( + runtime, + uiManager->createNode( + tagFromValue(arguments[0]), + stringFromValue(runtime, arguments[1]), + surfaceIdFromValue(runtime, arguments[2]), + RawProps(runtime, arguments[3]), + std::move(instanceHandle))); + } catch (const std::logic_error& ex) { + LOG(FATAL) << "logic_error in createNode: " << ex.what(); } - - return valueFromShadowNode( - runtime, - uiManager->createNode( - tagFromValue(arguments[0]), - stringFromValue(runtime, arguments[1]), - surfaceIdFromValue(runtime, arguments[2]), - RawProps(runtime, arguments[3]), - std::move(instanceHandle))); }); } @@ -267,7 +271,9 @@ jsi::Value UIManagerBinding::get( return valueFromShadowNode( runtime, uiManager->cloneNode( - *shadowNodeFromValue(runtime, arguments[0]))); + *shadowNodeFromValue(runtime, arguments[0]), + nullptr, + RawProps())); }); } @@ -347,7 +353,8 @@ jsi::Value UIManagerBinding::get( uiManager->cloneNode( *shadowNodeFromValue(runtime, arguments[0]), count > 1 ? shadowNodeListFromValue(runtime, arguments[1]) - : ShadowNode::emptySharedShadowNodeSharedList())); + : ShadowNode::emptySharedShadowNodeSharedList(), + RawProps())); }); } @@ -365,13 +372,12 @@ jsi::Value UIManagerBinding::get( size_t count) -> jsi::Value { validateArgumentCount(runtime, methodName, paramCount, count); - RawProps rawProps(runtime, arguments[1]); return valueFromShadowNode( runtime, uiManager->cloneNode( *shadowNodeFromValue(runtime, arguments[0]), nullptr, - &rawProps)); + RawProps(runtime, arguments[1]))); }); } @@ -392,7 +398,6 @@ jsi::Value UIManagerBinding::get( // validateArgumentCount(runtime, methodName, paramCount, count); bool hasChildrenArg = count == 3; - RawProps rawProps(runtime, arguments[hasChildrenArg ? 2 : 1]); return valueFromShadowNode( runtime, uiManager->cloneNode( @@ -400,7 +405,7 @@ jsi::Value UIManagerBinding::get( hasChildrenArg ? shadowNodeListFromValue(runtime, arguments[1]) : ShadowNode::emptySharedShadowNodeSharedList(), - &rawProps)); + RawProps(runtime, arguments[hasChildrenArg ? 2 : 1]))); }); } diff --git a/packages/react-native/ReactCommon/react/runtime/JSEngineInstance.h b/packages/react-native/ReactCommon/react/runtime/JSEngineInstance.h deleted file mode 100644 index 30cf7025c96eaf..00000000000000 --- a/packages/react-native/ReactCommon/react/runtime/JSEngineInstance.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include - -namespace facebook::react { - -/** - * Interface for a class that creates and owns an instance of a JS VM - */ -class JSEngineInstance { - public: - virtual std::unique_ptr createJSRuntime( - std::shared_ptr msgQueueThread) noexcept = 0; - - virtual ~JSEngineInstance() = default; -}; - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.cpp b/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.cpp new file mode 100644 index 00000000000000..a0b11fe6686a02 --- /dev/null +++ b/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "JSRuntimeFactory.h" + +namespace facebook::react { +jsi::Runtime& JSIRuntimeHolder::getRuntime() noexcept { + return *runtime_; +} + +JSIRuntimeHolder::JSIRuntimeHolder(std::unique_ptr runtime) + : runtime_(std::move(runtime)) { + assert(runtime_ != nullptr); +} +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.h b/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.h new file mode 100644 index 00000000000000..110c1f26590967 --- /dev/null +++ b/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +/** + * An interface that represents an instance of a JS VM + */ +class JSRuntime { + public: + virtual jsi::Runtime& getRuntime() noexcept = 0; + + virtual ~JSRuntime() = default; +}; + +/** + * Interface for a class that creates instances of a JS VM + */ +class JSRuntimeFactory { + public: + virtual std::unique_ptr createJSRuntime( + std::shared_ptr msgQueueThread) noexcept = 0; + + virtual ~JSRuntimeFactory() = default; +}; + +/** + * Utility class for creating a JSRuntime from a uniquely owned jsi::Runtime. + */ +class JSIRuntimeHolder : public JSRuntime { + public: + jsi::Runtime& getRuntime() noexcept override; + + explicit JSIRuntimeHolder(std::unique_ptr runtime); + + private: + std::unique_ptr runtime_; +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/runtime/React-RuntimeHermes.podspec b/packages/react-native/ReactCommon/react/runtime/React-RuntimeHermes.podspec index 54dcb839fdf598..b8bd53b8aac458 100644 --- a/packages/react-native/ReactCommon/react/runtime/React-RuntimeHermes.podspec +++ b/packages/react-native/ReactCommon/react/runtime/React-RuntimeHermes.podspec @@ -48,6 +48,7 @@ Pod::Spec.new do |s| s.dependency "React-jsitracing" s.dependency "React-utils" s.dependency "React-jsi" + s.dependency "React-RuntimeCore" if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1" s.dependency "hermes-engine" diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp index d671bace703efc..76b8029d258e46 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp @@ -26,7 +26,7 @@ namespace facebook::react { ReactInstance::ReactInstance( - std::unique_ptr runtime, + std::unique_ptr runtime, std::shared_ptr jsMessageQueueThread, std::shared_ptr timerManager, JsErrorHandler::JsErrorHandlingFunc jsErrorHandlingFunc, @@ -36,7 +36,7 @@ ReactInstance::ReactInstance( timerManager_(std::move(timerManager)), jsErrorHandler_(jsErrorHandlingFunc), hasFatalJsError_(std::make_shared(false)) { - auto runtimeExecutor = [weakRuntime = std::weak_ptr(runtime_), + auto runtimeExecutor = [weakRuntime = std::weak_ptr(runtime_), weakTimerManager = std::weak_ptr(timerManager_), weakJsMessageQueueThread = @@ -63,20 +63,20 @@ ReactInstance::ReactInstance( sharedJsMessageQueueThread->runOnQueue( [weakRuntime, weakTimerManager, callback = std::move(callback)]() { if (auto strongRuntime = weakRuntime.lock()) { + jsi::Runtime& jsiRuntime = strongRuntime->getRuntime(); SystraceSection s("ReactInstance::_runtimeExecutor[Callback]"); try { - callback(*strongRuntime); + callback(jsiRuntime); // If we have first-class support for microtasks, // they would've been called as part of the previous callback. if (!CoreFeatures::enableMicrotasks) { if (auto strongTimerManager = weakTimerManager.lock()) { - strongTimerManager->callReactNativeMicrotasks( - *strongRuntime); + strongTimerManager->callReactNativeMicrotasks(jsiRuntime); } } } catch (jsi::JSError& originalError) { - handleJSError(*strongRuntime, originalError, true); + handleJSError(jsiRuntime, originalError, true); } } }); diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h index 0d1762af01c529..caad761b7f07f5 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace facebook::react { @@ -29,7 +30,7 @@ class ReactInstance final { using BindingsInstallFunc = std::function; ReactInstance( - std::unique_ptr runtime, + std::unique_ptr runtime, std::shared_ptr jsMessageQueueThread, std::shared_ptr timerManager, JsErrorHandler::JsErrorHandlingFunc JsErrorHandlingFunc, @@ -64,7 +65,7 @@ class ReactInstance final { void handleMemoryPressureJs(int pressureLevel); private: - std::shared_ptr runtime_; + std::shared_ptr runtime_; std::shared_ptr jsMessageQueueThread_; std::shared_ptr bufferedRuntimeExecutor_; std::shared_ptr timerManager_; diff --git a/packages/react-native/ReactCommon/react/runtime/hermes/CMakeLists.txt b/packages/react-native/ReactCommon/react/runtime/hermes/CMakeLists.txt index 955bb14c946a6a..e46f159bd12f96 100644 --- a/packages/react-native/ReactCommon/react/runtime/hermes/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/runtime/hermes/CMakeLists.txt @@ -22,6 +22,7 @@ target_link_libraries(bridgelesshermes hermes_inspector_modern jsi hermes_executor_common + bridgeless ) if(${CMAKE_BUILD_TYPE} MATCHES Debug) diff --git a/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp b/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp index d682224485af81..0918259c77e93c 100644 --- a/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp @@ -89,7 +89,7 @@ class DecoratedRuntime : public jsi::RuntimeDecorator { #endif -std::unique_ptr HermesInstance::createJSRuntime( +std::unique_ptr HermesInstance::createJSRuntime( std::shared_ptr reactNativeConfig, std::shared_ptr<::hermes::vm::CrashManager> cm, std::shared_ptr msgQueueThread) noexcept { @@ -144,10 +144,10 @@ std::unique_ptr HermesInstance::createJSRuntime( std::unique_ptr decoratedRuntime = std::make_unique( std::move(hermesRuntime), msgQueueThread); - return decoratedRuntime; + return std::make_unique(std::move(decoratedRuntime)); #endif - return hermesRuntime; + return std::make_unique(std::move(hermesRuntime)); } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.h b/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.h index 63f3f73ba42f84..71b08d2fd5b07c 100644 --- a/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.h @@ -11,12 +11,13 @@ #include #include #include +#include namespace facebook::react { class HermesInstance { public: - static std::unique_ptr createJSRuntime( + static std::unique_ptr createJSRuntime( std::shared_ptr reactNativeConfig, std::shared_ptr<::hermes::vm::CrashManager> cm, std::shared_ptr msgQueueThread) noexcept; diff --git a/packages/react-native/ReactCommon/react/runtime/iostests/RCTHostTests.mm b/packages/react-native/ReactCommon/react/runtime/iostests/RCTHostTests.mm index 606d2d9dabd1f1..de2e016b95afc4 100644 --- a/packages/react-native/ReactCommon/react/runtime/iostests/RCTHostTests.mm +++ b/packages/react-native/ReactCommon/react/runtime/iostests/RCTHostTests.mm @@ -56,7 +56,7 @@ - (void)setUp _subject = [[RCTHost alloc] initWithBundleURL:OCMClassMock([NSURL class]) hostDelegate:_mockHostDelegate turboModuleManagerDelegate:OCMProtocolMock(@protocol(RCTTurboModuleManagerDelegate)) - jsEngineProvider:^std::shared_ptr() { + jsEngineProvider:^std::shared_ptr() { return std::make_shared(); }]; } diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHermesInstance.h b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHermesInstance.h index 0f3722443945dc..533aa82b92459e 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHermesInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHermesInstance.h @@ -10,7 +10,7 @@ #import #import #import -#import +#import #import namespace facebook { @@ -19,14 +19,14 @@ using CrashManagerProvider = std::function()>; // ObjC++ wrapper for HermesInstance.cpp -class RCTHermesInstance : public JSEngineInstance { +class RCTHermesInstance : public JSRuntimeFactory { public: RCTHermesInstance(); RCTHermesInstance( std::shared_ptr reactNativeConfig, CrashManagerProvider crashManagerProvider); - std::unique_ptr createJSRuntime( + std::unique_ptr createJSRuntime( std::shared_ptr msgQueueThread) noexcept override; ~RCTHermesInstance(){}; diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHermesInstance.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHermesInstance.mm index 04335ccd9c2a13..c3e4951ded603e 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHermesInstance.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHermesInstance.mm @@ -20,7 +20,7 @@ { } -std::unique_ptr RCTHermesInstance::createJSRuntime( +std::unique_ptr RCTHermesInstance::createJSRuntime( std::shared_ptr msgQueueThread) noexcept { return _hermesInstance->createJSRuntime( diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.h b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.h index 3dc528f8a506ec..124504a638f997 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.h +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.h @@ -9,7 +9,7 @@ #import #import -#import +#import #import "RCTInstance.h" @@ -53,7 +53,7 @@ NS_ASSUME_NONNULL_BEGIN @end -typedef std::shared_ptr (^RCTHostJSEngineProvider)(void); +typedef std::shared_ptr (^RCTHostJSEngineProvider)(void); @interface RCTHost : NSObject diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm index 53ddc5cab4368b..64daf56c38d7be 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm @@ -147,7 +147,7 @@ - (void)start [_instance invalidate]; } _instance = [[RCTInstance alloc] initWithDelegate:self - jsEngineInstance:[self _provideJSEngine] + jsRuntimeFactory:[self _provideJSEngine] bundleManager:_bundleManager turboModuleManagerDelegate:_turboModuleManagerDelegate onInitialBundleLoad:_onInitialBundleLoad @@ -214,7 +214,7 @@ - (void)didReceiveReloadCommand } _instance = [[RCTInstance alloc] initWithDelegate:self - jsEngineInstance:[self _provideJSEngine] + jsRuntimeFactory:[self _provideJSEngine] bundleManager:_bundleManager turboModuleManagerDelegate:_turboModuleManagerDelegate onInitialBundleLoad:_onInitialBundleLoad @@ -301,10 +301,10 @@ - (void)_attachSurface:(RCTFabricSurface *)surface return surfaces; } -- (std::shared_ptr)_provideJSEngine +- (std::shared_ptr)_provideJSEngine { RCTAssert(_jsEngineProvider, @"_jsEngineProvider must be non-nil"); - std::shared_ptr jsEngine = _jsEngineProvider(); + std::shared_ptr jsEngine = _jsEngineProvider(); RCTAssert(jsEngine != nullptr, @"_jsEngineProvider must return a nonnull pointer"); return jsEngine; diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.h b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.h index 79e9ff50e2e9ee..047dc38af97774 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.h @@ -9,7 +9,7 @@ #import #import -#import +#import #import #import "RCTContextContainerHandling.h" @@ -68,7 +68,7 @@ typedef void (^_Null_unspecified RCTInstanceInitialBundleLoadCompletionBlock)(); @interface RCTInstance : NSObject - (instancetype)initWithDelegate:(id)delegate - jsEngineInstance:(std::shared_ptr)jsEngineInstance + jsRuntimeFactory:(std::shared_ptr)jsRuntimeFactory bundleManager:(RCTBundleManager *)bundleManager turboModuleManagerDelegate:(id)turboModuleManagerDelegate onInitialBundleLoad:(RCTInstanceInitialBundleLoadCompletionBlock)onInitialBundleLoad diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm index bf5bd8fe6ba42d..6ed73ed4d85814 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm @@ -67,7 +67,7 @@ @interface RCTInstance () @implementation RCTInstance { std::unique_ptr _reactInstance; - std::shared_ptr _jsEngineInstance; + std::shared_ptr _jsRuntimeFactory; __weak id _appTMMDelegate; __weak id _delegate; RCTSurfacePresenter *_surfacePresenter; @@ -86,7 +86,7 @@ @implementation RCTInstance { #pragma mark - Public - (instancetype)initWithDelegate:(id)delegate - jsEngineInstance:(std::shared_ptr)jsEngineInstance + jsRuntimeFactory:(std::shared_ptr)jsRuntimeFactory bundleManager:(RCTBundleManager *)bundleManager turboModuleManagerDelegate:(id)tmmDelegate onInitialBundleLoad:(RCTInstanceInitialBundleLoadCompletionBlock)onInitialBundleLoad @@ -98,7 +98,7 @@ - (instancetype)initWithDelegate:(id)delegate [_performanceLogger markStartForTag:RCTPLReactInstanceInit]; _delegate = delegate; - _jsEngineInstance = jsEngineInstance; + _jsRuntimeFactory = jsRuntimeFactory; _appTMMDelegate = tmmDelegate; _jsThreadManager = [RCTJSThreadManager new]; _onInitialBundleLoad = onInitialBundleLoad; @@ -149,7 +149,7 @@ - (void)invalidate // Clean up all the Resources self->_reactInstance = nullptr; - self->_jsEngineInstance = nullptr; + self->_jsRuntimeFactory = nullptr; self->_appTMMDelegate = nil; self->_delegate = nil; self->_displayLink = nil; @@ -223,7 +223,7 @@ - (void)_start // Create the React Instance _reactInstance = std::make_unique( - _jsEngineInstance->createJSRuntime(_jsThreadManager.jsMessageThread), + _jsRuntimeFactory->createJSRuntime(_jsThreadManager.jsMessageThread), _jsThreadManager.jsMessageThread, timerManager, jsErrorHandlingFunc, diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTJscInstance.h b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTJscInstance.h index bcb1393519d1b8..bdd653287d0c15 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTJscInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTJscInstance.h @@ -7,16 +7,16 @@ #import #import -#import +#import namespace facebook { namespace react { -class RCTJscInstance : public JSEngineInstance { +class RCTJscInstance : public JSRuntimeFactory { public: RCTJscInstance(); - std::unique_ptr createJSRuntime( + std::unique_ptr createJSRuntime( std::shared_ptr msgQueueThread) noexcept override; ~RCTJscInstance(){}; diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTJscInstance.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTJscInstance.mm index 168ddc3aa1228c..c56c466909de90 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTJscInstance.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTJscInstance.mm @@ -13,10 +13,9 @@ RCTJscInstance::RCTJscInstance() {} -std::unique_ptr RCTJscInstance::createJSRuntime( - std::shared_ptr msgQueueThread) noexcept +std::unique_ptr RCTJscInstance::createJSRuntime(std::shared_ptr msgQueueThread) noexcept { - return jsc::makeJSCRuntime(); + return std::make_unique(jsc::makeJSCRuntime()); } } // namespace react diff --git a/packages/react-native/ReactCommon/react/runtime/tests/cxx/ReactInstanceTest.cpp b/packages/react-native/ReactCommon/react/runtime/tests/cxx/ReactInstanceTest.cpp index 0d8ea7f3285006..3f8a36b39daa83 100644 --- a/packages/react-native/ReactCommon/react/runtime/tests/cxx/ReactInstanceTest.cpp +++ b/packages/react-native/ReactCommon/react/runtime/tests/cxx/ReactInstanceTest.cpp @@ -116,8 +116,9 @@ class ReactInstanceTest : public ::testing::Test { ReactInstanceTest() {} void SetUp() override { - auto runtime = hermes::makeHermesRuntime(); - runtime_ = runtime.get(); + auto runtime = + std::make_unique(hermes::makeHermesRuntime()); + runtime_ = &runtime->getRuntime(); messageQueueThread_ = std::make_shared(); auto mockRegistry = std::make_unique(); mockRegistry_ = mockRegistry.get(); diff --git a/packages/react-native/ReactCommon/react/test_utils/ios/Shims/ShimRCTInstance.mm b/packages/react-native/ReactCommon/react/test_utils/ios/Shims/ShimRCTInstance.mm index 77476f9dfd3d52..884448d45b2c84 100644 --- a/packages/react-native/ReactCommon/react/test_utils/ios/Shims/ShimRCTInstance.mm +++ b/packages/react-native/ReactCommon/react/test_utils/ios/Shims/ShimRCTInstance.mm @@ -23,7 +23,7 @@ - (instancetype)init [RCTInstance class], [ShimRCTInstance class], @selector(initWithDelegate: - jsEngineInstance:bundleManager:turboModuleManagerDelegate:onInitialBundleLoad:moduleRegistry:)); + jsRuntimeFactory:bundleManager:turboModuleManagerDelegate:onInitialBundleLoad:moduleRegistry:)); RCTSwizzleInstanceSelector([RCTInstance class], [ShimRCTInstance class], @selector(invalidate)); RCTSwizzleInstanceSelector( [RCTInstance class], [ShimRCTInstance class], @selector(callFunctionOnJSModule:method:args:)); @@ -38,7 +38,7 @@ - (void)reset [RCTInstance class], [ShimRCTInstance class], @selector(initWithDelegate: - jsEngineInstance:bundleManager:turboModuleManagerDelegate:onInitialBundleLoad:moduleRegistry:)); + jsRuntimeFactory:bundleManager:turboModuleManagerDelegate:onInitialBundleLoad:moduleRegistry:)); RCTSwizzleInstanceSelector([RCTInstance class], [ShimRCTInstance class], @selector(invalidate)); RCTSwizzleInstanceSelector( [RCTInstance class], [ShimRCTInstance class], @selector(callFunctionOnJSModule:method:args:)); @@ -47,7 +47,7 @@ - (void)reset } - (instancetype)initWithDelegate:(id)delegate - jsEngineInstance:(std::shared_ptr)jsEngineInstance + jsRuntimeFactory:(std::shared_ptr)jsRuntimeFactory bundleManager:(RCTBundleManager *)bundleManager turboModuleManagerDelegate:(id)tmmDelegate onInitialBundleLoad:(RCTInstanceInitialBundleLoadCompletionBlock)onInitialBundleLoad diff --git a/packages/react-native/ReactCommon/react/utils/CoreFeatures.cpp b/packages/react-native/ReactCommon/react/utils/CoreFeatures.cpp index 6bdcc5d651e05e..2cd2e161c530c7 100644 --- a/packages/react-native/ReactCommon/react/utils/CoreFeatures.cpp +++ b/packages/react-native/ReactCommon/react/utils/CoreFeatures.cpp @@ -17,12 +17,12 @@ bool CoreFeatures::enableGranularScrollViewStateUpdatesIOS = false; bool CoreFeatures::enableMountHooks = false; bool CoreFeatures::doNotSwapLeftAndRightOnAndroidInLTR = false; bool CoreFeatures::enableCleanParagraphYogaNode = false; -bool CoreFeatures::disableScrollEventThrottleRequirement = false; bool CoreFeatures::enableGranularShadowTreeStateReconciliation = false; bool CoreFeatures::enableDefaultAsyncBatchedPriority = false; bool CoreFeatures::enableClonelessStateProgression = false; bool CoreFeatures::excludeYogaFromRawProps = false; bool CoreFeatures::enableMicrotasks = false; bool CoreFeatures::enableReportEventPaintTime = false; +bool CoreFeatures::positionRelativeDefault = false; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/utils/CoreFeatures.h b/packages/react-native/ReactCommon/react/utils/CoreFeatures.h index 2a377625791e66..ffc81e01e7247b 100644 --- a/packages/react-native/ReactCommon/react/utils/CoreFeatures.h +++ b/packages/react-native/ReactCommon/react/utils/CoreFeatures.h @@ -47,10 +47,6 @@ class CoreFeatures { // Clean yoga node when does not change. static bool enableCleanParagraphYogaNode; - // Fire `onScroll` events continuously on iOS without a `scrollEventThrottle` - // props, and provide continuous `onScroll` upates like other platforms. - static bool disableScrollEventThrottleRequirement; - // When enabled, the renderer would only fail commits when they propagate // state and the last commit that updated state changed before committing. static bool enableGranularShadowTreeStateReconciliation; @@ -71,6 +67,9 @@ class CoreFeatures { // Report paint time inside the Event Timing API implementation // (PerformanceObserver). static bool enableReportEventPaintTime; + + // Sets the default position of nodes to be relative instead of static + static bool positionRelativeDefault; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h index e1197444db8274..e0454394dae4d8 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h @@ -12,7 +12,7 @@ YG_EXTERN_C_BEGIN -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGAlign, YGAlignAuto, YGAlignFlexStart, @@ -24,23 +24,23 @@ YG_ENUM_SEQ_DECL( YGAlignSpaceAround, YGAlignSpaceEvenly) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGDimension, YGDimensionWidth, YGDimensionHeight) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGDirection, YGDirectionInherit, YGDirectionLTR, YGDirectionRTL) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGDisplay, YGDisplayFlex, YGDisplayNone) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGEdge, YGEdgeLeft, YGEdgeTop, @@ -62,25 +62,25 @@ YG_ENUM_DECL( YGErrataClassic = 2147483646) YG_DEFINE_ENUM_FLAG_OPERATORS(YGErrata) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGExperimentalFeature, YGExperimentalFeatureWebFlexBasis, YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGFlexDirection, YGFlexDirectionColumn, YGFlexDirectionColumnReverse, YGFlexDirectionRow, YGFlexDirectionRowReverse) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGGutter, YGGutterColumn, YGGutterRow, YGGutterAll) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGJustify, YGJustifyFlexStart, YGJustifyCenter, @@ -89,7 +89,7 @@ YG_ENUM_SEQ_DECL( YGJustifySpaceAround, YGJustifySpaceEvenly) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGLogLevel, YGLogLevelError, YGLogLevelWarn, @@ -98,24 +98,24 @@ YG_ENUM_SEQ_DECL( YGLogLevelVerbose, YGLogLevelFatal) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGMeasureMode, YGMeasureModeUndefined, YGMeasureModeExactly, YGMeasureModeAtMost) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGNodeType, YGNodeTypeDefault, YGNodeTypeText) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGOverflow, YGOverflowVisible, YGOverflowHidden, YGOverflowScroll) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGPositionType, YGPositionTypeStatic, YGPositionTypeRelative, @@ -128,14 +128,14 @@ YG_ENUM_DECL( YGPrintOptionsChildren = 4) YG_DEFINE_ENUM_FLAG_OPERATORS(YGPrintOptions) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGUnit, YGUnitUndefined, YGUnitPoint, YGUnitPercent, YGUnitAuto) -YG_ENUM_SEQ_DECL( +YG_ENUM_DECL( YGWrap, YGWrapNoWrap, YGWrapWrap, diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGMacros.h b/packages/react-native/ReactCommon/yoga/yoga/YGMacros.h index 07ddb1903b99a8..6460297a3d1684 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGMacros.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGMacros.h @@ -88,40 +88,6 @@ #define YG_DEFINE_ENUM_FLAG_OPERATORS(name) #endif -#ifdef __cplusplus - -namespace facebook::yoga { - -template -constexpr int -ordinalCount(); // can't use `= delete` due to a defect in clang < 3.9 - -namespace detail { -template -constexpr int n() { - return sizeof...(xs); -} -} // namespace detail - -} // namespace facebook::yoga -#endif - #define YG_ENUM_DECL(NAME, ...) \ typedef YG_ENUM_BEGIN(NAME){__VA_ARGS__} YG_ENUM_END(NAME); \ YG_EXPORT const char* NAME##ToString(NAME); - -#ifdef __cplusplus -#define YG_ENUM_SEQ_DECL(NAME, ...) \ - YG_ENUM_DECL(NAME, __VA_ARGS__) \ - YG_EXTERN_C_END \ - \ - namespace facebook::yoga { \ - template <> \ - constexpr int ordinalCount() { \ - return detail::n<__VA_ARGS__>(); \ - } \ - } \ - YG_EXTERN_C_BEGIN -#else -#define YG_ENUM_SEQ_DECL YG_ENUM_DECL -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp index 38d8f319161cc8..50cfd98f20af3e 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp @@ -351,13 +351,13 @@ bool YGNodeCanUseCachedMeasurement( float marginColumn, YGConfigRef config) { return yoga::canUseCachedMeasurement( - scopedEnum(widthMode), + sizingMode(scopedEnum(widthMode)), availableWidth, - scopedEnum(heightMode), + sizingMode(scopedEnum(heightMode)), availableHeight, - scopedEnum(lastWidthMode), + sizingMode(scopedEnum(lastWidthMode)), lastAvailableWidth, - scopedEnum(lastHeightMode), + sizingMode(scopedEnum(lastHeightMode)), lastAvailableHeight, lastComputedWidth, lastComputedHeight, diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNode.h b/packages/react-native/ReactCommon/yoga/yoga/YGNode.h index 61a2bc4ea5f7f5..b267cde14808d7 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNode.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNode.h @@ -186,6 +186,19 @@ typedef struct YGSize { } YGSize; /** + * Returns the computed dimensions of the node, following the contraints of + * `widthMode` and `heightMode`: + * + * YGMeasureModeUndefined: The parent has not imposed any constraint on the + * child. It can be whatever size it wants. + * + * YGMeasureModeAtMost: The child can be as large as it wants up to the + * specified size. + * + * YGMeasureModeExactly: The parent has determined an exact size for the + * child. The child is going to be given those bounds regardless of how big it + * wants to be. + * * @returns the size of the leaf node, measured under the given contraints. */ typedef YGSize (*YGMeasureFunc)( diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.cpp index 39f67f9dc9792b..d2477f72cf21f2 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNodeLayout.cpp @@ -7,6 +7,7 @@ #include #include +#include #include using namespace facebook; @@ -15,50 +16,48 @@ using namespace facebook::yoga; namespace { template -float getResolvedLayoutProperty( - const YGNodeConstRef nodeRef, - const YGEdge edge) { +float getResolvedLayoutProperty(const YGNodeConstRef nodeRef, const Edge edge) { const auto node = resolveRef(nodeRef); yoga::assertFatalWithNode( node, - edge <= YGEdgeEnd, + edge <= Edge::End, "Cannot get layout properties of multi-edge shorthands"); - if (edge == YGEdgeStart) { + if (edge == Edge::Start) { if (node->getLayout().direction() == Direction::RTL) { - return (node->getLayout().*LayoutMember)[YGEdgeRight]; + return (node->getLayout().*LayoutMember)(Edge::Right); } else { - return (node->getLayout().*LayoutMember)[YGEdgeLeft]; + return (node->getLayout().*LayoutMember)(Edge::Left); } } - if (edge == YGEdgeEnd) { + if (edge == Edge::End) { if (node->getLayout().direction() == Direction::RTL) { - return (node->getLayout().*LayoutMember)[YGEdgeLeft]; + return (node->getLayout().*LayoutMember)(Edge::Left); } else { - return (node->getLayout().*LayoutMember)[YGEdgeRight]; + return (node->getLayout().*LayoutMember)(Edge::Right); } } - return (node->getLayout().*LayoutMember)[edge]; + return (node->getLayout().*LayoutMember)(edge); } } // namespace float YGNodeLayoutGetLeft(const YGNodeConstRef node) { - return resolveRef(node)->getLayout().position[YGEdgeLeft]; + return resolveRef(node)->getLayout().position(Edge::Left); } float YGNodeLayoutGetTop(const YGNodeConstRef node) { - return resolveRef(node)->getLayout().position[YGEdgeTop]; + return resolveRef(node)->getLayout().position(Edge::Top); } float YGNodeLayoutGetRight(const YGNodeConstRef node) { - return resolveRef(node)->getLayout().position[YGEdgeRight]; + return resolveRef(node)->getLayout().position(Edge::Right); } float YGNodeLayoutGetBottom(const YGNodeConstRef node) { - return resolveRef(node)->getLayout().position[YGEdgeBottom]; + return resolveRef(node)->getLayout().position(Edge::Bottom); } float YGNodeLayoutGetWidth(const YGNodeConstRef node) { @@ -78,13 +77,16 @@ bool YGNodeLayoutGetHadOverflow(const YGNodeConstRef node) { } float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge) { - return getResolvedLayoutProperty<&LayoutResults::margin>(node, edge); + return getResolvedLayoutProperty<&LayoutResults::margin>( + node, scopedEnum(edge)); } float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge) { - return getResolvedLayoutProperty<&LayoutResults::border>(node, edge); + return getResolvedLayoutProperty<&LayoutResults::border>( + node, scopedEnum(edge)); } float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge) { - return getResolvedLayoutProperty<&LayoutResults::padding>(node, edge); + return getResolvedLayoutProperty<&LayoutResults::padding>( + node, scopedEnum(edge)); } diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp index 57d352cd01685d..14f2dc3062270e 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNodeStyle.cpp @@ -14,58 +14,26 @@ using namespace facebook::yoga; namespace { -template -void updateStyle( - yoga::Node* node, - T value, - NeedsUpdate&& needsUpdate, - Update&& update) { - if (needsUpdate(node->getStyle(), value)) { - update(node->getStyle(), value); - node->markDirtyAndPropagate(); +template +void updateStyle(YGNodeRef node, ValueT value) { + auto& style = resolveRef(node)->getStyle(); + if ((style.*GetterT)() != value) { + (style.*SetterT)(value); + resolveRef(node)->markDirtyAndPropagate(); } } -template -void updateStyle(YGNodeRef node, Ref (Style::*prop)(), T value) { - updateStyle( - resolveRef(node), - value, - [prop](Style& s, T x) { return (s.*prop)() != x; }, - [prop](Style& s, T x) { (s.*prop)() = x; }); -} - -template -void updateIndexedStyleProp( - YGNodeRef node, - Ref (Style::*prop)(), - Idx idx, - CompactValue value) { - updateStyle( - resolveRef(node), - value, - [idx, prop](Style& s, CompactValue x) { return (s.*prop)()[idx] != x; }, - [idx, prop](Style& s, CompactValue x) { (s.*prop)()[idx] = x; }); -} - -template -void updateIndexedStyleProp(YGNodeRef node, IdxT idx, CompactValue value) { - updateStyle( - resolveRef(node), - value, - [idx](Style& s, CompactValue x) { return (s.*GetterT)(idx) != x; }, - [idx](Style& s, CompactValue x) { (s.*SetterT)(idx, x); }); +template +void updateStyle(YGNodeRef node, IdxT idx, ValueT value) { + auto& style = resolveRef(node)->getStyle(); + if ((style.*GetterT)(idx) != value) { + (style.*SetterT)(idx, value); + resolveRef(node)->markDirtyAndPropagate(); + } } } // namespace -// MSVC has trouble inferring the return type of pointer to member functions -// with const and non-const overloads, instead of preferring the non-const -// overload like clang and GCC. For the purposes of updateStyle(), we can help -// MSVC by specifying that return type explicitly. In combination with -// decltype, MSVC will prefer the non-const version. -#define MSVC_HINT(PROP) decltype(Style{}.PROP()) - void YGNodeCopyStyle( const YGNodeRef dstNodeRef, const YGNodeConstRef srcNodeRef) { @@ -79,7 +47,7 @@ void YGNodeCopyStyle( } void YGNodeStyleSetDirection(const YGNodeRef node, const YGDirection value) { - updateStyle(node, &Style::direction, scopedEnum(value)); + updateStyle<&Style::direction, &Style::setDirection>(node, scopedEnum(value)); } YGDirection YGNodeStyleGetDirection(const YGNodeConstRef node) { @@ -89,8 +57,8 @@ YGDirection YGNodeStyleGetDirection(const YGNodeConstRef node) { void YGNodeStyleSetFlexDirection( const YGNodeRef node, const YGFlexDirection flexDirection) { - updateStyle( - node, &Style::flexDirection, scopedEnum(flexDirection)); + updateStyle<&Style::flexDirection, &Style::setFlexDirection>( + node, scopedEnum(flexDirection)); } YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeConstRef node) { @@ -100,8 +68,8 @@ YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeConstRef node) { void YGNodeStyleSetJustifyContent( const YGNodeRef node, const YGJustify justifyContent) { - updateStyle( - node, &Style::justifyContent, scopedEnum(justifyContent)); + updateStyle<&Style::justifyContent, &Style::setJustifyContent>( + node, scopedEnum(justifyContent)); } YGJustify YGNodeStyleGetJustifyContent(const YGNodeConstRef node) { @@ -111,8 +79,8 @@ YGJustify YGNodeStyleGetJustifyContent(const YGNodeConstRef node) { void YGNodeStyleSetAlignContent( const YGNodeRef node, const YGAlign alignContent) { - updateStyle( - node, &Style::alignContent, scopedEnum(alignContent)); + updateStyle<&Style::alignContent, &Style::setAlignContent>( + node, scopedEnum(alignContent)); } YGAlign YGNodeStyleGetAlignContent(const YGNodeConstRef node) { @@ -120,8 +88,8 @@ YGAlign YGNodeStyleGetAlignContent(const YGNodeConstRef node) { } void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) { - updateStyle( - node, &Style::alignItems, scopedEnum(alignItems)); + updateStyle<&Style::alignItems, &Style::setAlignItems>( + node, scopedEnum(alignItems)); } YGAlign YGNodeStyleGetAlignItems(const YGNodeConstRef node) { @@ -129,8 +97,8 @@ YGAlign YGNodeStyleGetAlignItems(const YGNodeConstRef node) { } void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) { - updateStyle( - node, &Style::alignSelf, scopedEnum(alignSelf)); + updateStyle<&Style::alignSelf, &Style::setAlignSelf>( + node, scopedEnum(alignSelf)); } YGAlign YGNodeStyleGetAlignSelf(const YGNodeConstRef node) { @@ -140,8 +108,8 @@ YGAlign YGNodeStyleGetAlignSelf(const YGNodeConstRef node) { void YGNodeStyleSetPositionType( const YGNodeRef node, const YGPositionType positionType) { - updateStyle( - node, &Style::positionType, scopedEnum(positionType)); + updateStyle<&Style::positionType, &Style::setPositionType>( + node, scopedEnum(positionType)); } YGPositionType YGNodeStyleGetPositionType(const YGNodeConstRef node) { @@ -149,8 +117,8 @@ YGPositionType YGNodeStyleGetPositionType(const YGNodeConstRef node) { } void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) { - updateStyle( - node, &Style::flexWrap, scopedEnum(flexWrap)); + updateStyle<&Style::flexWrap, &Style::setFlexWrap>( + node, scopedEnum(flexWrap)); } YGWrap YGNodeStyleGetFlexWrap(const YGNodeConstRef node) { @@ -158,8 +126,8 @@ YGWrap YGNodeStyleGetFlexWrap(const YGNodeConstRef node) { } void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) { - updateStyle( - node, &Style::overflow, scopedEnum(overflow)); + updateStyle<&Style::overflow, &Style::setOverflow>( + node, scopedEnum(overflow)); } YGOverflow YGNodeStyleGetOverflow(const YGNodeConstRef node) { @@ -167,7 +135,7 @@ YGOverflow YGNodeStyleGetOverflow(const YGNodeConstRef node) { } void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) { - updateStyle(node, &Style::display, scopedEnum(display)); + updateStyle<&Style::display, &Style::setDisplay>(node, scopedEnum(display)); } YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) { @@ -175,7 +143,7 @@ YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) { } void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { - updateStyle(node, &Style::flex, FloatOptional{flex}); + updateStyle<&Style::flex, &Style::setFlex>(node, FloatOptional{flex}); } float YGNodeStyleGetFlex(const YGNodeConstRef nodeRef) { @@ -186,8 +154,8 @@ float YGNodeStyleGetFlex(const YGNodeConstRef nodeRef) { } void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) { - updateStyle( - node, &Style::flexGrow, FloatOptional{flexGrow}); + updateStyle<&Style::flexGrow, &Style::setFlexGrow>( + node, FloatOptional{flexGrow}); } float YGNodeStyleGetFlexGrow(const YGNodeConstRef nodeRef) { @@ -198,8 +166,8 @@ float YGNodeStyleGetFlexGrow(const YGNodeConstRef nodeRef) { } void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) { - updateStyle( - node, &Style::flexShrink, FloatOptional{flexShrink}); + updateStyle<&Style::flexShrink, &Style::setFlexShrink>( + node, FloatOptional{flexShrink}); } float YGNodeStyleGetFlexShrink(const YGNodeConstRef nodeRef) { @@ -211,20 +179,19 @@ float YGNodeStyleGetFlexShrink(const YGNodeConstRef nodeRef) { } void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) { - auto value = CompactValue::ofMaybe(flexBasis); - updateStyle(node, &Style::flexBasis, value); + updateStyle<&Style::flexBasis, &Style::setFlexBasis>( + node, value::points(flexBasis)); } void YGNodeStyleSetFlexBasisPercent( const YGNodeRef node, const float flexBasisPercent) { - auto value = CompactValue::ofMaybe(flexBasisPercent); - updateStyle(node, &Style::flexBasis, value); + updateStyle<&Style::flexBasis, &Style::setFlexBasis>( + node, value::percent(flexBasisPercent)); } void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) { - updateStyle( - node, &Style::flexBasis, CompactValue::ofAuto()); + updateStyle<&Style::flexBasis, &Style::setFlexBasis>(node, value::ofAuto()); } YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) { @@ -236,66 +203,62 @@ YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) { } void YGNodeStyleSetPosition(YGNodeRef node, YGEdge edge, float points) { - auto value = CompactValue::ofMaybe(points); - updateIndexedStyleProp( - node, &Style::position, edge, value); + updateStyle<&Style::position, &Style::setPosition>( + node, scopedEnum(edge), value::points(points)); } void YGNodeStyleSetPositionPercent(YGNodeRef node, YGEdge edge, float percent) { - auto value = CompactValue::ofMaybe(percent); - updateIndexedStyleProp( - node, &Style::position, edge, value); + updateStyle<&Style::position, &Style::setPosition>( + node, scopedEnum(edge), value::percent(percent)); } YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge) { - return resolveRef(node)->getStyle().position()[edge]; + return resolveRef(node)->getStyle().position(scopedEnum(edge)); } void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float points) { - auto value = CompactValue::ofMaybe(points); - updateIndexedStyleProp(node, &Style::margin, edge, value); + updateStyle<&Style::margin, &Style::setMargin>( + node, scopedEnum(edge), value::points(points)); } void YGNodeStyleSetMarginPercent(YGNodeRef node, YGEdge edge, float percent) { - auto value = CompactValue::ofMaybe(percent); - updateIndexedStyleProp(node, &Style::margin, edge, value); + updateStyle<&Style::margin, &Style::setMargin>( + node, scopedEnum(edge), value::percent(percent)); } void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge) { - updateIndexedStyleProp( - node, &Style::margin, edge, CompactValue::ofAuto()); + updateStyle<&Style::margin, &Style::setMargin>( + node, scopedEnum(edge), value::ofAuto()); } YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge) { - return resolveRef(node)->getStyle().margin()[edge]; + return resolveRef(node)->getStyle().margin(scopedEnum(edge)); } void YGNodeStyleSetPadding(YGNodeRef node, YGEdge edge, float points) { - auto value = CompactValue::ofMaybe(points); - updateIndexedStyleProp( - node, &Style::padding, edge, value); + updateStyle<&Style::padding, &Style::setPadding>( + node, scopedEnum(edge), value::points(points)); } void YGNodeStyleSetPaddingPercent(YGNodeRef node, YGEdge edge, float percent) { - auto value = CompactValue::ofMaybe(percent); - updateIndexedStyleProp( - node, &Style::padding, edge, value); + updateStyle<&Style::padding, &Style::setPadding>( + node, scopedEnum(edge), value::percent(percent)); } YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge) { - return resolveRef(node)->getStyle().padding()[edge]; + return resolveRef(node)->getStyle().padding(scopedEnum(edge)); } void YGNodeStyleSetBorder( const YGNodeRef node, const YGEdge edge, const float border) { - auto value = CompactValue::ofMaybe(border); - updateIndexedStyleProp(node, &Style::border, edge, value); + updateStyle<&Style::border, &Style::setBorder>( + node, scopedEnum(edge), value::points(border)); } float YGNodeStyleGetBorder(const YGNodeConstRef node, const YGEdge edge) { - auto border = resolveRef(node)->getStyle().border()[edge]; + auto border = resolveRef(node)->getStyle().border(scopedEnum(edge)); if (border.isUndefined() || border.isAuto()) { return YGUndefined; } @@ -307,9 +270,8 @@ void YGNodeStyleSetGap( const YGNodeRef node, const YGGutter gutter, const float gapLength) { - auto length = CompactValue::ofMaybe(gapLength); - updateIndexedStyleProp<&Style::gap, &Style::setGap>( - node, scopedEnum(gutter), length); + updateStyle<&Style::gap, &Style::setGap>( + node, scopedEnum(gutter), value::points(gapLength)); } float YGNodeStyleGetGap(const YGNodeConstRef node, const YGGutter gutter) { @@ -322,8 +284,8 @@ float YGNodeStyleGetGap(const YGNodeConstRef node, const YGGutter gutter) { } void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) { - updateStyle( - node, &Style::aspectRatio, FloatOptional{aspectRatio}); + updateStyle<&Style::aspectRatio, &Style::setAspectRatio>( + node, FloatOptional{aspectRatio}); } float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) { @@ -332,20 +294,18 @@ float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) { } void YGNodeStyleSetWidth(YGNodeRef node, float points) { - auto value = CompactValue::ofMaybe(points); - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Width, value); + updateStyle<&Style::dimension, &Style::setDimension>( + node, Dimension::Width, value::points(points)); } void YGNodeStyleSetWidthPercent(YGNodeRef node, float percent) { - auto value = CompactValue::ofMaybe(percent); - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Width, value); + updateStyle<&Style::dimension, &Style::setDimension>( + node, Dimension::Width, value::percent(percent)); } void YGNodeStyleSetWidthAuto(YGNodeRef node) { - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Width, CompactValue::ofAuto()); + updateStyle<&Style::dimension, &Style::setDimension>( + node, Dimension::Width, value::ofAuto()); } YGValue YGNodeStyleGetWidth(YGNodeConstRef node) { @@ -353,20 +313,18 @@ YGValue YGNodeStyleGetWidth(YGNodeConstRef node) { } void YGNodeStyleSetHeight(YGNodeRef node, float points) { - auto value = CompactValue::ofMaybe(points); - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Height, value); + updateStyle<&Style::dimension, &Style::setDimension>( + node, Dimension::Height, value::points(points)); } void YGNodeStyleSetHeightPercent(YGNodeRef node, float percent) { - auto value = CompactValue::ofMaybe(percent); - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Height, value); + updateStyle<&Style::dimension, &Style::setDimension>( + node, Dimension::Height, value::percent(percent)); } void YGNodeStyleSetHeightAuto(YGNodeRef node) { - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Height, CompactValue::ofAuto()); + updateStyle<&Style::dimension, &Style::setDimension>( + node, Dimension::Height, value::ofAuto()); } YGValue YGNodeStyleGetHeight(YGNodeConstRef node) { @@ -374,15 +332,13 @@ YGValue YGNodeStyleGetHeight(YGNodeConstRef node) { } void YGNodeStyleSetMinWidth(const YGNodeRef node, const float minWidth) { - auto value = CompactValue::ofMaybe(minWidth); - updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( - node, Dimension::Width, value); + updateStyle<&Style::minDimension, &Style::setMinDimension>( + node, Dimension::Width, value::points(minWidth)); } void YGNodeStyleSetMinWidthPercent(const YGNodeRef node, const float minWidth) { - auto value = CompactValue::ofMaybe(minWidth); - updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( - node, Dimension::Width, value); + updateStyle<&Style::minDimension, &Style::setMinDimension>( + node, Dimension::Width, value::percent(minWidth)); } YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) { @@ -390,17 +346,15 @@ YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) { } void YGNodeStyleSetMinHeight(const YGNodeRef node, const float minHeight) { - auto value = CompactValue::ofMaybe(minHeight); - updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( - node, Dimension::Height, value); + updateStyle<&Style::minDimension, &Style::setMinDimension>( + node, Dimension::Height, value::points(minHeight)); } void YGNodeStyleSetMinHeightPercent( const YGNodeRef node, const float minHeight) { - auto value = CompactValue::ofMaybe(minHeight); - updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( - node, Dimension::Height, value); + updateStyle<&Style::minDimension, &Style::setMinDimension>( + node, Dimension::Height, value::percent(minHeight)); } YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) { @@ -408,15 +362,13 @@ YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) { } void YGNodeStyleSetMaxWidth(const YGNodeRef node, const float maxWidth) { - auto value = CompactValue::ofMaybe(maxWidth); - updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( - node, Dimension::Width, value); + updateStyle<&Style::maxDimension, &Style::setMaxDimension>( + node, Dimension::Width, value::points(maxWidth)); } void YGNodeStyleSetMaxWidthPercent(const YGNodeRef node, const float maxWidth) { - auto value = CompactValue::ofMaybe(maxWidth); - updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( - node, Dimension::Width, value); + updateStyle<&Style::maxDimension, &Style::setMaxDimension>( + node, Dimension::Width, value::percent(maxWidth)); } YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) { @@ -424,17 +376,15 @@ YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) { } void YGNodeStyleSetMaxHeight(const YGNodeRef node, const float maxHeight) { - auto value = CompactValue::ofMaybe(maxHeight); - updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( - node, Dimension::Height, value); + updateStyle<&Style::maxDimension, &Style::setMaxDimension>( + node, Dimension::Height, value::points(maxHeight)); } void YGNodeStyleSetMaxHeightPercent( const YGNodeRef node, const float maxHeight) { - auto value = CompactValue::ofMaybe(maxHeight); - updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( - node, Dimension::Height, value); + updateStyle<&Style::maxDimension, &Style::setMaxDimension>( + node, Dimension::Height, value::percent(maxHeight)); } YGValue YGNodeStyleGetMaxHeight(const YGNodeConstRef node) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/Baseline.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/Baseline.cpp index aea316c03526f7..a86b9b28a48db1 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/Baseline.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/Baseline.cpp @@ -57,7 +57,7 @@ float calculateBaseline(const yoga::Node* node) { } const float baseline = calculateBaseline(baselineChild); - return baseline + baselineChild->getLayout().position[YGEdgeTop]; + return baseline + baselineChild->getLayout().position(Edge::Top); } bool isBaselineLayout(const yoga::Node* node) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/Cache.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/Cache.cpp index 7496e873e04ce4..9154fc6ce9cc87 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/Cache.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/Cache.cpp @@ -12,51 +12,52 @@ namespace facebook::yoga { static inline bool sizeIsExactAndMatchesOldMeasuredSize( - MeasureMode sizeMode, + SizingMode sizeMode, float size, float lastComputedSize) { - return sizeMode == MeasureMode::Exactly && + return sizeMode == SizingMode::StretchFit && yoga::inexactEquals(size, lastComputedSize); } -static inline bool oldSizeIsUnspecifiedAndStillFits( - MeasureMode sizeMode, +static inline bool oldSizeIsMaxContentAndStillFits( + SizingMode sizeMode, float size, - MeasureMode lastSizeMode, + SizingMode lastSizeMode, float lastComputedSize) { - return sizeMode == MeasureMode::AtMost && - lastSizeMode == MeasureMode::Undefined && + return sizeMode == SizingMode::FitContent && + lastSizeMode == SizingMode::MaxContent && (size >= lastComputedSize || yoga::inexactEquals(size, lastComputedSize)); } -static inline bool newMeasureSizeIsStricterAndStillValid( - MeasureMode sizeMode, +static inline bool newSizeIsStricterAndStillValid( + SizingMode sizeMode, float size, - MeasureMode lastSizeMode, + SizingMode lastSizeMode, float lastSize, float lastComputedSize) { - return lastSizeMode == MeasureMode::AtMost && - sizeMode == MeasureMode::AtMost && !std::isnan(lastSize) && - !std::isnan(size) && !std::isnan(lastComputedSize) && lastSize > size && + return lastSizeMode == SizingMode::FitContent && + sizeMode == SizingMode::FitContent && yoga::isDefined(lastSize) && + yoga::isDefined(size) && yoga::isDefined(lastComputedSize) && + lastSize > size && (lastComputedSize <= size || yoga::inexactEquals(size, lastComputedSize)); } bool canUseCachedMeasurement( - const MeasureMode widthMode, + const SizingMode widthMode, const float availableWidth, - const MeasureMode heightMode, + const SizingMode heightMode, const float availableHeight, - const MeasureMode lastWidthMode, + const SizingMode lastWidthMode, const float lastAvailableWidth, - const MeasureMode lastHeightMode, + const SizingMode lastHeightMode, const float lastAvailableHeight, const float lastComputedWidth, const float lastComputedHeight, const float marginRow, const float marginColumn, const yoga::Config* const config) { - if ((!std::isnan(lastComputedHeight) && lastComputedHeight < 0) || - (!std::isnan(lastComputedWidth) && lastComputedWidth < 0)) { + if ((yoga::isDefined(lastComputedHeight) && lastComputedHeight < 0) || + ((yoga::isDefined(lastComputedWidth)) && lastComputedWidth < 0)) { return false; } @@ -87,33 +88,32 @@ bool canUseCachedMeasurement( hasSameWidthSpec || sizeIsExactAndMatchesOldMeasuredSize( widthMode, availableWidth - marginRow, lastComputedWidth) || - oldSizeIsUnspecifiedAndStillFits( + oldSizeIsMaxContentAndStillFits( widthMode, availableWidth - marginRow, lastWidthMode, lastComputedWidth) || - newMeasureSizeIsStricterAndStillValid( + newSizeIsStricterAndStillValid( widthMode, availableWidth - marginRow, lastWidthMode, lastAvailableWidth, lastComputedWidth); - const bool heightIsCompatible = - hasSameHeightSpec || + const bool heightIsCompatible = hasSameHeightSpec || sizeIsExactAndMatchesOldMeasuredSize( - heightMode, availableHeight - marginColumn, lastComputedHeight) || - oldSizeIsUnspecifiedAndStillFits( - heightMode, - availableHeight - marginColumn, - lastHeightMode, - lastComputedHeight) || - newMeasureSizeIsStricterAndStillValid( - heightMode, - availableHeight - marginColumn, - lastHeightMode, - lastAvailableHeight, - lastComputedHeight); + heightMode, + availableHeight - marginColumn, + lastComputedHeight) || + oldSizeIsMaxContentAndStillFits(heightMode, + availableHeight - marginColumn, + lastHeightMode, + lastComputedHeight) || + newSizeIsStricterAndStillValid(heightMode, + availableHeight - marginColumn, + lastHeightMode, + lastAvailableHeight, + lastComputedHeight); return widthIsCompatible && heightIsCompatible; } diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/Cache.h b/packages/react-native/ReactCommon/yoga/yoga/algorithm/Cache.h index 31b91d5f791ead..f8857eaf35c947 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/Cache.h +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/Cache.h @@ -7,19 +7,19 @@ #pragma once +#include #include -#include namespace facebook::yoga { bool canUseCachedMeasurement( - MeasureMode widthMode, + SizingMode widthMode, float availableWidth, - MeasureMode heightMode, + SizingMode heightMode, float availableHeight, - MeasureMode lastWidthMode, + SizingMode lastWidthMode, float lastAvailableWidth, - MeasureMode lastHeightMode, + SizingMode lastHeightMode, float lastAvailableHeight, float lastComputedWidth, float lastComputedHeight, diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp index c1026c9adcf823..fe97b4e1166482 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -39,8 +40,8 @@ bool calculateLayoutInternal( const float availableWidth, const float availableHeight, const Direction ownerDirection, - const MeasureMode widthMeasureMode, - const MeasureMode heightMeasureMode, + const SizingMode widthSizingMode, + const SizingMode heightSizingMode, const float ownerWidth, const float ownerHeight, const bool performLayout, @@ -88,7 +89,7 @@ static void setChildTrailingPosition( const float size = child->getLayout().measuredDimension(dimension(axis)); child->setLayoutPosition( node->getLayout().measuredDimension(dimension(axis)) - size - - child->getLayout().position[flexStartEdge(axis)], + child->getLayout().position(flexStartEdge(axis)), flexEndEdge(axis)); } @@ -97,22 +98,22 @@ static void constrainMaxSizeForMode( const enum FlexDirection axis, const float ownerAxisSize, const float ownerWidth, - MeasureMode* mode, + SizingMode* mode, float* size) { const FloatOptional maxSize = yoga::resolveValue( node->getStyle().maxDimension(dimension(axis)), ownerAxisSize) + FloatOptional(node->getMarginForAxis(axis, ownerWidth)); switch (*mode) { - case MeasureMode::Exactly: - case MeasureMode::AtMost: + case SizingMode::StretchFit: + case SizingMode::FitContent: *size = (maxSize.isUndefined() || *size < maxSize.unwrap()) ? *size : maxSize.unwrap(); break; - case MeasureMode::Undefined: + case SizingMode::MaxContent: if (maxSize.isDefined()) { - *mode = MeasureMode::AtMost; + *mode = SizingMode::FitContent; *size = maxSize.unwrap(); } break; @@ -123,11 +124,11 @@ static void computeFlexBasisForChild( const yoga::Node* const node, yoga::Node* const child, const float width, - const MeasureMode widthMode, + const SizingMode widthMode, const float height, const float ownerWidth, const float ownerHeight, - const MeasureMode heightMode, + const SizingMode heightMode, const Direction direction, LayoutData& layoutMarkerData, const uint32_t depth, @@ -140,8 +141,8 @@ static void computeFlexBasisForChild( float childWidth; float childHeight; - MeasureMode childWidthMeasureMode; - MeasureMode childHeightMeasureMode; + SizingMode childWidthSizingMode; + SizingMode childHeightSizingMode; const FloatOptional resolvedFlexBasis = yoga::resolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize); @@ -182,8 +183,8 @@ static void computeFlexBasisForChild( // basis). childWidth = YGUndefined; childHeight = YGUndefined; - childWidthMeasureMode = MeasureMode::Undefined; - childHeightMeasureMode = MeasureMode::Undefined; + childWidthSizingMode = SizingMode::MaxContent; + childHeightSizingMode = SizingMode::MaxContent; auto marginRow = child->getMarginForAxis(FlexDirection::Row, ownerWidth); auto marginColumn = @@ -195,7 +196,7 @@ static void computeFlexBasisForChild( child->getResolvedDimension(Dimension::Width), ownerWidth) .unwrap() + marginRow; - childWidthMeasureMode = MeasureMode::Exactly; + childWidthSizingMode = SizingMode::StretchFit; } if (isColumnStyleDimDefined) { childHeight = @@ -203,7 +204,7 @@ static void computeFlexBasisForChild( child->getResolvedDimension(Dimension::Height), ownerHeight) .unwrap() + marginColumn; - childHeightMeasureMode = MeasureMode::Exactly; + childHeightSizingMode = SizingMode::StretchFit; } // The W3C spec doesn't say anything about the 'overflow' property, but all @@ -212,7 +213,7 @@ static void computeFlexBasisForChild( node->getStyle().overflow() != Overflow::Scroll) { if (yoga::isUndefined(childWidth) && yoga::isDefined(width)) { childWidth = width; - childWidthMeasureMode = MeasureMode::AtMost; + childWidthSizingMode = SizingMode::FitContent; } } @@ -220,21 +221,21 @@ static void computeFlexBasisForChild( node->getStyle().overflow() != Overflow::Scroll) { if (yoga::isUndefined(childHeight) && yoga::isDefined(height)) { childHeight = height; - childHeightMeasureMode = MeasureMode::AtMost; + childHeightSizingMode = SizingMode::FitContent; } } const auto& childStyle = child->getStyle(); if (childStyle.aspectRatio().isDefined()) { - if (!isMainAxisRow && childWidthMeasureMode == MeasureMode::Exactly) { + if (!isMainAxisRow && childWidthSizingMode == SizingMode::StretchFit) { childHeight = marginColumn + (childWidth - marginRow) / childStyle.aspectRatio().unwrap(); - childHeightMeasureMode = MeasureMode::Exactly; + childHeightSizingMode = SizingMode::StretchFit; } else if ( - isMainAxisRow && childHeightMeasureMode == MeasureMode::Exactly) { + isMainAxisRow && childHeightSizingMode == SizingMode::StretchFit) { childWidth = marginRow + (childHeight - marginColumn) * childStyle.aspectRatio().unwrap(); - childWidthMeasureMode = MeasureMode::Exactly; + childWidthSizingMode = SizingMode::StretchFit; } } @@ -242,35 +243,35 @@ static void computeFlexBasisForChild( // the cross axis to be measured exactly with the available inner width const bool hasExactWidth = - yoga::isDefined(width) && widthMode == MeasureMode::Exactly; + yoga::isDefined(width) && widthMode == SizingMode::StretchFit; const bool childWidthStretch = resolveChildAlignment(node, child) == Align::Stretch && - childWidthMeasureMode != MeasureMode::Exactly; + childWidthSizingMode != SizingMode::StretchFit; if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth && childWidthStretch) { childWidth = width; - childWidthMeasureMode = MeasureMode::Exactly; + childWidthSizingMode = SizingMode::StretchFit; if (childStyle.aspectRatio().isDefined()) { childHeight = (childWidth - marginRow) / childStyle.aspectRatio().unwrap(); - childHeightMeasureMode = MeasureMode::Exactly; + childHeightSizingMode = SizingMode::StretchFit; } } const bool hasExactHeight = - yoga::isDefined(height) && heightMode == MeasureMode::Exactly; + yoga::isDefined(height) && heightMode == SizingMode::StretchFit; const bool childHeightStretch = resolveChildAlignment(node, child) == Align::Stretch && - childHeightMeasureMode != MeasureMode::Exactly; + childHeightSizingMode != SizingMode::StretchFit; if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight && childHeightStretch) { childHeight = height; - childHeightMeasureMode = MeasureMode::Exactly; + childHeightSizingMode = SizingMode::StretchFit; if (childStyle.aspectRatio().isDefined()) { childWidth = (childHeight - marginColumn) * childStyle.aspectRatio().unwrap(); - childWidthMeasureMode = MeasureMode::Exactly; + childWidthSizingMode = SizingMode::StretchFit; } } @@ -279,14 +280,14 @@ static void computeFlexBasisForChild( FlexDirection::Row, ownerWidth, ownerWidth, - &childWidthMeasureMode, + &childWidthSizingMode, &childWidth); constrainMaxSizeForMode( child, FlexDirection::Column, ownerHeight, ownerWidth, - &childHeightMeasureMode, + &childHeightSizingMode, &childHeight); // Measure the child @@ -295,8 +296,8 @@ static void computeFlexBasisForChild( childWidth, childHeight, direction, - childWidthMeasureMode, - childHeightMeasureMode, + childWidthSizingMode, + childHeightSizingMode, ownerWidth, ownerHeight, false, @@ -316,7 +317,7 @@ static void layoutAbsoluteChild( const yoga::Node* const node, yoga::Node* const child, const float width, - const MeasureMode widthMode, + const SizingMode widthMode, const float height, const Direction direction, LayoutData& layoutMarkerData, @@ -329,8 +330,8 @@ static void layoutAbsoluteChild( float childWidth = YGUndefined; float childHeight = YGUndefined; - MeasureMode childWidthMeasureMode = MeasureMode::Undefined; - MeasureMode childHeightMeasureMode = MeasureMode::Undefined; + SizingMode childWidthSizingMode = SizingMode::MaxContent; + SizingMode childHeightSizingMode = SizingMode::MaxContent; auto marginRow = child->getMarginForAxis(FlexDirection::Row, width); auto marginColumn = child->getMarginForAxis(FlexDirection::Column, width); @@ -395,22 +396,22 @@ static void layoutAbsoluteChild( // If we're still missing one or the other dimension, measure the content. if (yoga::isUndefined(childWidth) || yoga::isUndefined(childHeight)) { - childWidthMeasureMode = yoga::isUndefined(childWidth) - ? MeasureMode::Undefined - : MeasureMode::Exactly; - childHeightMeasureMode = yoga::isUndefined(childHeight) - ? MeasureMode::Undefined - : MeasureMode::Exactly; + childWidthSizingMode = yoga::isUndefined(childWidth) + ? SizingMode::MaxContent + : SizingMode::StretchFit; + childHeightSizingMode = yoga::isUndefined(childHeight) + ? SizingMode::MaxContent + : SizingMode::StretchFit; // If the size of the owner is defined then try to constrain the absolute // child to that size as well. This allows text within the absolute child to // wrap to the size of its owner. This is the same behavior as many browsers // implement. if (!isMainAxisRow && yoga::isUndefined(childWidth) && - widthMode != MeasureMode::Undefined && yoga::isDefined(width) && + widthMode != SizingMode::MaxContent && yoga::isDefined(width) && width > 0) { childWidth = width; - childWidthMeasureMode = MeasureMode::AtMost; + childWidthSizingMode = SizingMode::FitContent; } calculateLayoutInternal( @@ -418,8 +419,8 @@ static void layoutAbsoluteChild( childWidth, childHeight, direction, - childWidthMeasureMode, - childHeightMeasureMode, + childWidthSizingMode, + childHeightSizingMode, childWidth, childHeight, false, @@ -438,8 +439,8 @@ static void layoutAbsoluteChild( childWidth, childHeight, direction, - MeasureMode::Exactly, - MeasureMode::Exactly, + SizingMode::StretchFit, + SizingMode::StretchFit, childWidth, childHeight, true, @@ -534,8 +535,8 @@ static void measureNodeWithMeasureFunc( yoga::Node* const node, float availableWidth, float availableHeight, - const MeasureMode widthMeasureMode, - const MeasureMode heightMeasureMode, + const SizingMode widthSizingMode, + const SizingMode heightSizingMode, const float ownerWidth, const float ownerHeight, LayoutData& layoutMarkerData, @@ -545,19 +546,20 @@ static void measureNodeWithMeasureFunc( node->hasMeasureFunc(), "Expected node to have custom measure function"); - if (widthMeasureMode == MeasureMode::Undefined) { + if (widthSizingMode == SizingMode::MaxContent) { availableWidth = YGUndefined; } - if (heightMeasureMode == MeasureMode::Undefined) { + if (heightSizingMode == SizingMode::MaxContent) { availableHeight = YGUndefined; } - const auto& padding = node->getLayout().padding; - const auto& border = node->getLayout().border; - const float paddingAndBorderAxisRow = padding[YGEdgeLeft] + - padding[YGEdgeRight] + border[YGEdgeLeft] + border[YGEdgeRight]; - const float paddingAndBorderAxisColumn = padding[YGEdgeTop] + - padding[YGEdgeBottom] + border[YGEdgeTop] + border[YGEdgeBottom]; + const auto& layout = node->getLayout(); + const float paddingAndBorderAxisRow = layout.padding(Edge::Left) + + layout.padding(Edge::Right) + layout.border(Edge::Left) + + layout.border(Edge::Right); + const float paddingAndBorderAxisColumn = layout.padding(Edge::Top) + + layout.padding(Edge::Bottom) + layout.border(Edge::Top) + + layout.border(Edge::Bottom); // We want to make sure we don't call measure with negative size const float innerWidth = yoga::isUndefined(availableWidth) @@ -567,8 +569,8 @@ static void measureNodeWithMeasureFunc( ? availableHeight : yoga::maxOrDefined(0.0f, availableHeight - paddingAndBorderAxisColumn); - if (widthMeasureMode == MeasureMode::Exactly && - heightMeasureMode == MeasureMode::Exactly) { + if (widthSizingMode == SizingMode::StretchFit && + heightSizingMode == SizingMode::StretchFit) { // Don't bother sizing the text if both dimensions are already defined. node->setLayoutMeasuredDimension( boundAxis( @@ -587,7 +589,10 @@ static void measureNodeWithMeasureFunc( // Measure the text under the current constraints. const YGSize measuredSize = node->measure( - innerWidth, widthMeasureMode, innerHeight, heightMeasureMode); + innerWidth, + measureMode(widthSizingMode), + innerHeight, + measureMode(heightSizingMode)); layoutMarkerData.measureCallbacks += 1; layoutMarkerData.measureCallbackReasonsCount[static_cast(reason)] += @@ -596,9 +601,9 @@ static void measureNodeWithMeasureFunc( Event::publish( node, {innerWidth, - unscopedEnum(widthMeasureMode), + unscopedEnum(measureMode(widthSizingMode)), innerHeight, - unscopedEnum(heightMeasureMode), + unscopedEnum(measureMode(heightSizingMode)), measuredSize.width, measuredSize.height, reason}); @@ -607,8 +612,8 @@ static void measureNodeWithMeasureFunc( boundAxis( node, FlexDirection::Row, - (widthMeasureMode == MeasureMode::Undefined || - widthMeasureMode == MeasureMode::AtMost) + (widthSizingMode == SizingMode::MaxContent || + widthSizingMode == SizingMode::FitContent) ? measuredSize.width + paddingAndBorderAxisRow : availableWidth, ownerWidth, @@ -619,8 +624,8 @@ static void measureNodeWithMeasureFunc( boundAxis( node, FlexDirection::Column, - (heightMeasureMode == MeasureMode::Undefined || - heightMeasureMode == MeasureMode::AtMost) + (heightSizingMode == SizingMode::MaxContent || + heightSizingMode == SizingMode::FitContent) ? measuredSize.height + paddingAndBorderAxisColumn : availableHeight, ownerHeight, @@ -635,28 +640,27 @@ static void measureNodeWithoutChildren( yoga::Node* const node, const float availableWidth, const float availableHeight, - const MeasureMode widthMeasureMode, - const MeasureMode heightMeasureMode, + const SizingMode widthSizingMode, + const SizingMode heightSizingMode, const float ownerWidth, const float ownerHeight) { - const auto& padding = node->getLayout().padding; - const auto& border = node->getLayout().border; + const auto& layout = node->getLayout(); float width = availableWidth; - if (widthMeasureMode == MeasureMode::Undefined || - widthMeasureMode == MeasureMode::AtMost) { - width = padding[YGEdgeLeft] + padding[YGEdgeRight] + border[YGEdgeLeft] + - border[YGEdgeRight]; + if (widthSizingMode == SizingMode::MaxContent || + widthSizingMode == SizingMode::FitContent) { + width = layout.padding(Edge::Left) + layout.padding(Edge::Right) + + layout.border(Edge::Left) + layout.border(Edge::Right); } node->setLayoutMeasuredDimension( boundAxis(node, FlexDirection::Row, width, ownerWidth, ownerWidth), Dimension::Width); float height = availableHeight; - if (heightMeasureMode == MeasureMode::Undefined || - heightMeasureMode == MeasureMode::AtMost) { - height = padding[YGEdgeTop] + padding[YGEdgeBottom] + border[YGEdgeTop] + - border[YGEdgeBottom]; + if (heightSizingMode == SizingMode::MaxContent || + heightSizingMode == SizingMode::FitContent) { + height = layout.padding(Edge::Top) + layout.padding(Edge::Bottom) + + layout.border(Edge::Top) + layout.border(Edge::Bottom); } node->setLayoutMeasuredDimension( boundAxis(node, FlexDirection::Column, height, ownerHeight, ownerWidth), @@ -667,22 +671,22 @@ static bool measureNodeWithFixedSize( yoga::Node* const node, const float availableWidth, const float availableHeight, - const MeasureMode widthMeasureMode, - const MeasureMode heightMeasureMode, + const SizingMode widthSizingMode, + const SizingMode heightSizingMode, const float ownerWidth, const float ownerHeight) { if ((yoga::isDefined(availableWidth) && - widthMeasureMode == MeasureMode::AtMost && availableWidth <= 0.0f) || + widthSizingMode == SizingMode::FitContent && availableWidth <= 0.0f) || (yoga::isDefined(availableHeight) && - heightMeasureMode == MeasureMode::AtMost && availableHeight <= 0.0f) || - (widthMeasureMode == MeasureMode::Exactly && - heightMeasureMode == MeasureMode::Exactly)) { + heightSizingMode == SizingMode::FitContent && availableHeight <= 0.0f) || + (widthSizingMode == SizingMode::StretchFit && + heightSizingMode == SizingMode::StretchFit)) { node->setLayoutMeasuredDimension( boundAxis( node, FlexDirection::Row, yoga::isUndefined(availableWidth) || - (widthMeasureMode == MeasureMode::AtMost && + (widthSizingMode == SizingMode::FitContent && availableWidth < 0.0f) ? 0.0f : availableWidth, @@ -695,7 +699,7 @@ static bool measureNodeWithFixedSize( node, FlexDirection::Column, yoga::isUndefined(availableHeight) || - (heightMeasureMode == MeasureMode::AtMost && + (heightSizingMode == SizingMode::FitContent && availableHeight < 0.0f) ? 0.0f : availableHeight, @@ -755,8 +759,8 @@ static float computeFlexBasisForChildren( yoga::Node* const node, const float availableInnerWidth, const float availableInnerHeight, - MeasureMode widthMeasureMode, - MeasureMode heightMeasureMode, + SizingMode widthSizingMode, + SizingMode heightSizingMode, Direction direction, FlexDirection mainAxis, bool performLayout, @@ -766,12 +770,12 @@ static float computeFlexBasisForChildren( float totalOuterFlexBasis = 0.0f; YGNodeRef singleFlexChild = nullptr; const auto& children = node->getChildren(); - MeasureMode measureModeMainDim = - isRow(mainAxis) ? widthMeasureMode : heightMeasureMode; + SizingMode sizingModeMainDim = + isRow(mainAxis) ? widthSizingMode : heightSizingMode; // If there is only one child with flexGrow + flexShrink it means we can set // the computedFlexBasis to 0 instead of measuring and shrinking / flexing the // child to exactly match the remaining space - if (measureModeMainDim == MeasureMode::Exactly) { + if (sizingModeMainDim == SizingMode::StretchFit) { for (auto child : children) { if (child->isNodeFlexible()) { if (singleFlexChild != nullptr || @@ -818,11 +822,11 @@ static float computeFlexBasisForChildren( node, child, availableInnerWidth, - widthMeasureMode, + widthSizingMode, availableInnerHeight, availableInnerWidth, availableInnerHeight, - heightMeasureMode, + heightSizingMode, direction, layoutMarkerData, depth, @@ -852,7 +856,7 @@ static float distributeFreeSpaceSecondPass( const float availableInnerWidth, const float availableInnerHeight, const bool mainAxisOverflows, - const MeasureMode measureModeCrossDim, + const SizingMode sizingModeCrossDim, const bool performLayout, LayoutData& layoutMarkerData, const uint32_t depth, @@ -925,35 +929,35 @@ static float distributeFreeSpaceSecondPass( float childCrossSize; float childMainSize = updatedMainSize + marginMain; - MeasureMode childCrossMeasureMode; - MeasureMode childMainMeasureMode = MeasureMode::Exactly; + SizingMode childCrossSizingMode; + SizingMode childMainSizingMode = SizingMode::StretchFit; const auto& childStyle = currentLineChild->getStyle(); if (childStyle.aspectRatio().isDefined()) { childCrossSize = isMainAxisRow ? (childMainSize - marginMain) / childStyle.aspectRatio().unwrap() : (childMainSize - marginMain) * childStyle.aspectRatio().unwrap(); - childCrossMeasureMode = MeasureMode::Exactly; + childCrossSizingMode = SizingMode::StretchFit; childCrossSize += marginCross; } else if ( !std::isnan(availableInnerCrossDim) && !styleDefinesDimension( currentLineChild, crossAxis, availableInnerCrossDim) && - measureModeCrossDim == MeasureMode::Exactly && + sizingModeCrossDim == SizingMode::StretchFit && !(isNodeFlexWrap && mainAxisOverflows) && resolveChildAlignment(node, currentLineChild) == Align::Stretch && currentLineChild->getFlexStartMarginValue(crossAxis).unit != YGUnitAuto && currentLineChild->marginTrailingValue(crossAxis).unit != YGUnitAuto) { childCrossSize = availableInnerCrossDim; - childCrossMeasureMode = MeasureMode::Exactly; + childCrossSizingMode = SizingMode::StretchFit; } else if (!styleDefinesDimension( currentLineChild, crossAxis, availableInnerCrossDim)) { childCrossSize = availableInnerCrossDim; - childCrossMeasureMode = yoga::isUndefined(childCrossSize) - ? MeasureMode::Undefined - : MeasureMode::AtMost; + childCrossSizingMode = yoga::isUndefined(childCrossSize) + ? SizingMode::MaxContent + : SizingMode::FitContent; } else { childCrossSize = yoga::resolveValue( @@ -964,11 +968,11 @@ static float distributeFreeSpaceSecondPass( const bool isLoosePercentageMeasurement = currentLineChild->getResolvedDimension(dimension(crossAxis)).unit == YGUnitPercent && - measureModeCrossDim != MeasureMode::Exactly; - childCrossMeasureMode = + sizingModeCrossDim != SizingMode::StretchFit; + childCrossSizingMode = yoga::isUndefined(childCrossSize) || isLoosePercentageMeasurement - ? MeasureMode::Undefined - : MeasureMode::Exactly; + ? SizingMode::MaxContent + : SizingMode::StretchFit; } constrainMaxSizeForMode( @@ -976,14 +980,14 @@ static float distributeFreeSpaceSecondPass( mainAxis, availableInnerMainDim, availableInnerWidth, - &childMainMeasureMode, + &childMainSizingMode, &childMainSize); constrainMaxSizeForMode( currentLineChild, crossAxis, availableInnerCrossDim, availableInnerWidth, - &childCrossMeasureMode, + &childCrossSizingMode, &childCrossSize); const bool requiresStretchLayout = @@ -997,10 +1001,10 @@ static float distributeFreeSpaceSecondPass( const float childWidth = isMainAxisRow ? childMainSize : childCrossSize; const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize; - const MeasureMode childWidthMeasureMode = - isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode; - const MeasureMode childHeightMeasureMode = - !isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode; + const SizingMode childWidthSizingMode = + isMainAxisRow ? childMainSizingMode : childCrossSizingMode; + const SizingMode childHeightSizingMode = + !isMainAxisRow ? childMainSizingMode : childCrossSizingMode; const bool isLayoutPass = performLayout && !requiresStretchLayout; // Recursively call the layout algorithm for this child with the updated @@ -1010,8 +1014,8 @@ static float distributeFreeSpaceSecondPass( childWidth, childHeight, node->getLayout().direction(), - childWidthMeasureMode, - childHeightMeasureMode, + childWidthSizingMode, + childHeightSizingMode, availableInnerWidth, availableInnerHeight, isLayoutPass, @@ -1144,7 +1148,7 @@ static void resolveFlexibleLength( const float availableInnerWidth, const float availableInnerHeight, const bool mainAxisOverflows, - const MeasureMode measureModeCrossDim, + const SizingMode sizingModeCrossDim, const bool performLayout, LayoutData& layoutMarkerData, const uint32_t depth, @@ -1170,7 +1174,7 @@ static void resolveFlexibleLength( availableInnerWidth, availableInnerHeight, mainAxisOverflows, - measureModeCrossDim, + sizingModeCrossDim, performLayout, layoutMarkerData, depth, @@ -1186,8 +1190,8 @@ static void justifyMainAxis( const FlexDirection mainAxis, const FlexDirection crossAxis, const Direction direction, - const MeasureMode measureModeMainDim, - const MeasureMode measureModeCrossDim, + const SizingMode sizingModeMainDim, + const SizingMode sizingModeCrossDim, const float mainAxisownerSize, const float ownerWidth, const float availableInnerMainDim, @@ -1208,7 +1212,7 @@ static void justifyMainAxis( const float gap = node->getGapForAxis(mainAxis); // If we are using "at most" rules in the main axis, make sure that // remainingFreeSpace is 0 when min main dimension is not given - if (measureModeMainDim == MeasureMode::AtMost && + if (sizingModeMainDim == SizingMode::FitContent && flexLine.layout.remainingFreeSpace > 0) { if (style.minDimension(dimension(mainAxis)).isDefined() && yoga::resolveValue( @@ -1326,7 +1330,7 @@ static void justifyMainAxis( if (performLayout) { child->setLayoutPosition( - childLayout.position[flexStartEdge(mainAxis)] + + childLayout.position(flexStartEdge(mainAxis)) + flexLine.layout.mainDim, flexStartEdge(mainAxis)); } @@ -1340,7 +1344,7 @@ static void justifyMainAxis( static_cast(numberOfAutoMarginsOnCurrentLine); } bool canSkipFlex = - !performLayout && measureModeCrossDim == MeasureMode::Exactly; + !performLayout && sizingModeCrossDim == SizingMode::StretchFit; if (canSkipFlex) { // If we skipped the flex step, then we can't rely on the measuredDims // because they weren't computed. This means we can't call @@ -1382,7 +1386,7 @@ static void justifyMainAxis( } } else if (performLayout) { child->setLayoutPosition( - childLayout.position[flexStartEdge(mainAxis)] + + childLayout.position(flexStartEdge(mainAxis)) + node->getInlineStartBorder(mainAxis, direction) + leadingMainDim, flexStartEdge(mainAxis)); @@ -1432,9 +1436,9 @@ static void justifyMainAxis( // depends on layout flags // - ownerDirection: the inline (text) direction within the owner // (left-to-right or right-to-left) -// - widthMeasureMode: indicates the sizing rules for the width (see below +// - widthSizingMode: indicates the sizing rules for the width (see below // for explanation) -// - heightMeasureMode: indicates the sizing rules for the height (see below +// - heightSizingMode: indicates the sizing rules for the height (see below // for explanation) // - performLayout: specifies whether the caller is interested in just the // dimensions of the node or it requires the entire node and its subtree to @@ -1449,26 +1453,17 @@ static void justifyMainAxis( // layout.measuredDimensions field includes any border or padding for the // node but does not include margins. // -// The spec describes four different layout modes: "fill available", "max -// content", "min content", and "fit content". Of these, we don't use "min -// content" because we don't support default minimum main sizes (see above -// for details). Each of our measure modes maps to a layout mode from the -// spec (https://www.w3.org/TR/CSS3-sizing/#terms): -// - MeasureMode::Undefined: max content -// - MeasureMode::Exactly: fill available -// - MeasureMode::AtMost: fit content -// // When calling calculateLayoutImpl and calculateLayoutInternal, if the // caller passes an available size of undefined then it must also pass a -// measure mode of MeasureMode::Undefined in that dimension. +// measure mode of SizingMode::MaxContent in that dimension. // static void calculateLayoutImpl( yoga::Node* const node, const float availableWidth, const float availableHeight, const Direction ownerDirection, - const MeasureMode widthMeasureMode, - const MeasureMode heightMeasureMode, + const SizingMode widthSizingMode, + const SizingMode heightSizingMode, const float ownerWidth, const float ownerHeight, const bool performLayout, @@ -1479,17 +1474,17 @@ static void calculateLayoutImpl( yoga::assertFatalWithNode( node, yoga::isUndefined(availableWidth) - ? widthMeasureMode == MeasureMode::Undefined + ? widthSizingMode == SizingMode::MaxContent : true, - "availableWidth is indefinite so widthMeasureMode must be " - "MeasureMode::Undefined"); + "availableWidth is indefinite so widthSizingMode must be " + "SizingMode::MaxContent"); yoga::assertFatalWithNode( node, yoga::isUndefined(availableHeight) - ? heightMeasureMode == MeasureMode::Undefined + ? heightSizingMode == SizingMode::MaxContent : true, - "availableHeight is indefinite so heightMeasureMode must be " - "MeasureMode::Undefined"); + "availableHeight is indefinite so heightSizingMode must be " + "SizingMode::MaxContent"); (performLayout ? layoutMarkerData.layouts : layoutMarkerData.measures) += 1; @@ -1502,9 +1497,8 @@ static void calculateLayoutImpl( const FlexDirection flexColumnDirection = resolveDirection(FlexDirection::Column, direction); - const YGEdge startEdge = - direction == Direction::LTR ? YGEdgeLeft : YGEdgeRight; - const YGEdge endEdge = direction == Direction::LTR ? YGEdgeRight : YGEdgeLeft; + const Edge startEdge = direction == Direction::LTR ? Edge::Left : Edge::Right; + const Edge endEdge = direction == Direction::LTR ? Edge::Right : Edge::Left; const float marginRowLeading = node->getInlineStartMargin(flexRowDirection, direction, ownerWidth); @@ -1514,10 +1508,10 @@ static void calculateLayoutImpl( node->setLayoutMargin(marginRowTrailing, endEdge); const float marginColumnLeading = node->getInlineStartMargin(flexColumnDirection, direction, ownerWidth); - node->setLayoutMargin(marginColumnLeading, YGEdgeTop); + node->setLayoutMargin(marginColumnLeading, Edge::Top); const float marginColumnTrailing = node->getInlineEndMargin(flexColumnDirection, direction, ownerWidth); - node->setLayoutMargin(marginColumnTrailing, YGEdgeBottom); + node->setLayoutMargin(marginColumnTrailing, Edge::Bottom); const float marginAxisRow = marginRowLeading + marginRowTrailing; const float marginAxisColumn = marginColumnLeading + marginColumnTrailing; @@ -1527,9 +1521,9 @@ static void calculateLayoutImpl( node->setLayoutBorder( node->getInlineEndBorder(flexRowDirection, direction), endEdge); node->setLayoutBorder( - node->getInlineStartBorder(flexColumnDirection, direction), YGEdgeTop); + node->getInlineStartBorder(flexColumnDirection, direction), Edge::Top); node->setLayoutBorder( - node->getInlineEndBorder(flexColumnDirection, direction), YGEdgeBottom); + node->getInlineEndBorder(flexColumnDirection, direction), Edge::Bottom); node->setLayoutPadding( node->getInlineStartPadding(flexRowDirection, direction, ownerWidth), @@ -1539,18 +1533,18 @@ static void calculateLayoutImpl( endEdge); node->setLayoutPadding( node->getInlineStartPadding(flexColumnDirection, direction, ownerWidth), - YGEdgeTop); + Edge::Top); node->setLayoutPadding( node->getInlineEndPadding(flexColumnDirection, direction, ownerWidth), - YGEdgeBottom); + Edge::Bottom); if (node->hasMeasureFunc()) { measureNodeWithMeasureFunc( node, availableWidth - marginAxisRow, availableHeight - marginAxisColumn, - widthMeasureMode, - heightMeasureMode, + widthSizingMode, + heightSizingMode, ownerWidth, ownerHeight, layoutMarkerData, @@ -1564,8 +1558,8 @@ static void calculateLayoutImpl( node, availableWidth - marginAxisRow, availableHeight - marginAxisColumn, - widthMeasureMode, - heightMeasureMode, + widthSizingMode, + heightSizingMode, ownerWidth, ownerHeight); return; @@ -1578,8 +1572,8 @@ static void calculateLayoutImpl( node, availableWidth - marginAxisRow, availableHeight - marginAxisColumn, - widthMeasureMode, - heightMeasureMode, + widthSizingMode, + heightSizingMode, ownerWidth, ownerHeight)) { return; @@ -1608,10 +1602,10 @@ static void calculateLayoutImpl( const float leadingPaddingAndBorderCross = node->getInlineStartPaddingAndBorder(crossAxis, direction, ownerWidth); - MeasureMode measureModeMainDim = - isMainAxisRow ? widthMeasureMode : heightMeasureMode; - MeasureMode measureModeCrossDim = - isMainAxisRow ? heightMeasureMode : widthMeasureMode; + SizingMode sizingModeMainDim = + isMainAxisRow ? widthSizingMode : heightSizingMode; + SizingMode sizingModeCrossDim = + isMainAxisRow ? heightSizingMode : widthSizingMode; const float paddingAndBorderAxisRow = isMainAxisRow ? paddingAndBorderAxisMain : paddingAndBorderAxisCross; @@ -1646,8 +1640,8 @@ static void calculateLayoutImpl( node, availableInnerWidth, availableInnerHeight, - widthMeasureMode, - heightMeasureMode, + widthSizingMode, + heightSizingMode, direction, mainAxis, performLayout, @@ -1661,12 +1655,12 @@ static void calculateLayoutImpl( } const bool mainAxisOverflows = - (measureModeMainDim != MeasureMode::Undefined) && + (sizingModeMainDim != SizingMode::MaxContent) && totalMainDim > availableInnerMainDim; if (isNodeFlexWrap && mainAxisOverflows && - measureModeMainDim == MeasureMode::AtMost) { - measureModeMainDim = MeasureMode::Exactly; + sizingModeMainDim == SizingMode::FitContent) { + sizingModeMainDim = SizingMode::StretchFit; } // STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES @@ -1700,7 +1694,7 @@ static void calculateLayoutImpl( // If we don't need to measure the cross axis, we can skip the entire flex // step. const bool canSkipFlex = - !performLayout && measureModeCrossDim == MeasureMode::Exactly; + !performLayout && sizingModeCrossDim == SizingMode::StretchFit; // STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS // Calculate the remaining available space that needs to be allocated. If @@ -1710,7 +1704,7 @@ static void calculateLayoutImpl( bool sizeBasedOnContent = false; // If we don't measure with exact main dimension we want to ensure we don't // violate min and max - if (measureModeMainDim != MeasureMode::Exactly) { + if (sizingModeMainDim != SizingMode::StretchFit) { const auto& style = node->getStyle(); const float minInnerWidth = yoga::resolveValue(style.minDimension(Dimension::Width), ownerWidth) @@ -1783,7 +1777,7 @@ static void calculateLayoutImpl( availableInnerWidth, availableInnerHeight, mainAxisOverflows, - measureModeCrossDim, + sizingModeCrossDim, performLayout, layoutMarkerData, depth, @@ -1808,8 +1802,8 @@ static void calculateLayoutImpl( mainAxis, crossAxis, direction, - measureModeMainDim, - measureModeCrossDim, + sizingModeMainDim, + sizingModeCrossDim, mainAxisownerSize, ownerWidth, availableInnerMainDim, @@ -1818,8 +1812,8 @@ static void calculateLayoutImpl( performLayout); float containerCrossAxis = availableInnerCrossDim; - if (measureModeCrossDim == MeasureMode::Undefined || - measureModeCrossDim == MeasureMode::AtMost) { + if (sizingModeCrossDim == SizingMode::MaxContent || + sizingModeCrossDim == SizingMode::FitContent) { // Compute the cross axis from the max cross dimension of the children. containerCrossAxis = boundAxis( @@ -1832,7 +1826,7 @@ static void calculateLayoutImpl( } // If there's no flex wrap, the cross dimension is defined by the container. - if (!isNodeFlexWrap && measureModeCrossDim == MeasureMode::Exactly) { + if (!isNodeFlexWrap && sizingModeCrossDim == SizingMode::StretchFit) { flexLine.layout.crossDim = availableInnerCrossDim; } @@ -1873,7 +1867,7 @@ static void calculateLayoutImpl( // default to border + margin if (!isChildLeadingPosDefined || yoga::isUndefined( - child->getLayout().position[flexStartEdge(crossAxis)])) { + child->getLayout().position(flexStartEdge(crossAxis)))) { child->setLayoutPosition( node->getInlineStartBorder(crossAxis, direction) + child->getInlineStartMargin( @@ -1911,21 +1905,21 @@ static void calculateLayoutImpl( childMainSize += child->getMarginForAxis(mainAxis, availableInnerWidth); - MeasureMode childMainMeasureMode = MeasureMode::Exactly; - MeasureMode childCrossMeasureMode = MeasureMode::Exactly; + SizingMode childMainSizingMode = SizingMode::StretchFit; + SizingMode childCrossSizingMode = SizingMode::StretchFit; constrainMaxSizeForMode( child, mainAxis, availableInnerMainDim, availableInnerWidth, - &childMainMeasureMode, + &childMainSizingMode, &childMainSize); constrainMaxSizeForMode( child, crossAxis, availableInnerCrossDim, availableInnerWidth, - &childCrossMeasureMode, + &childCrossSizingMode, &childCrossSize); const float childWidth = @@ -1936,24 +1930,24 @@ static void calculateLayoutImpl( auto alignContent = node->getStyle().alignContent(); auto crossAxisDoesNotGrow = alignContent != Align::Stretch && isNodeFlexWrap; - const MeasureMode childWidthMeasureMode = + const SizingMode childWidthSizingMode = yoga::isUndefined(childWidth) || (!isMainAxisRow && crossAxisDoesNotGrow) - ? MeasureMode::Undefined - : MeasureMode::Exactly; - const MeasureMode childHeightMeasureMode = + ? SizingMode::MaxContent + : SizingMode::StretchFit; + const SizingMode childHeightSizingMode = yoga::isUndefined(childHeight) || (isMainAxisRow && crossAxisDoesNotGrow) - ? MeasureMode::Undefined - : MeasureMode::Exactly; + ? SizingMode::MaxContent + : SizingMode::StretchFit; calculateLayoutInternal( child, childWidth, childHeight, direction, - childWidthMeasureMode, - childHeightMeasureMode, + childWidthSizingMode, + childHeightSizingMode, availableInnerWidth, availableInnerHeight, true, @@ -1986,7 +1980,7 @@ static void calculateLayoutImpl( } // And we apply the position child->setLayoutPosition( - child->getLayout().position[flexStartEdge(crossAxis)] + + child->getLayout().position(flexStartEdge(crossAxis)) + totalLineCrossDim + leadingCrossDim, flexStartEdge(crossAxis)); } @@ -2174,8 +2168,8 @@ static void calculateLayoutImpl( childWidth, childHeight, direction, - MeasureMode::Exactly, - MeasureMode::Exactly, + SizingMode::StretchFit, + SizingMode::StretchFit, availableInnerWidth, availableInnerHeight, true, @@ -2195,7 +2189,7 @@ static void calculateLayoutImpl( FlexDirection::Column, direction, availableInnerCrossDim), - YGEdgeTop); + Edge::Top); break; } @@ -2234,9 +2228,9 @@ static void calculateLayoutImpl( // If the user didn't specify a width or height for the node, set the // dimensions based on the children. - if (measureModeMainDim == MeasureMode::Undefined || + if (sizingModeMainDim == SizingMode::MaxContent || (node->getStyle().overflow() != Overflow::Scroll && - measureModeMainDim == MeasureMode::AtMost)) { + sizingModeMainDim == SizingMode::FitContent)) { // Clamp the size to the min/max size, if specified, and make sure it // doesn't go below the padding and border amount. node->setLayoutMeasuredDimension( @@ -2245,7 +2239,7 @@ static void calculateLayoutImpl( dimension(mainAxis)); } else if ( - measureModeMainDim == MeasureMode::AtMost && + sizingModeMainDim == SizingMode::FitContent && node->getStyle().overflow() == Overflow::Scroll) { node->setLayoutMeasuredDimension( yoga::maxOrDefined( @@ -2261,9 +2255,9 @@ static void calculateLayoutImpl( dimension(mainAxis)); } - if (measureModeCrossDim == MeasureMode::Undefined || + if (sizingModeCrossDim == SizingMode::MaxContent || (node->getStyle().overflow() != Overflow::Scroll && - measureModeCrossDim == MeasureMode::AtMost)) { + sizingModeCrossDim == SizingMode::FitContent)) { // Clamp the size to the min/max size, if specified, and make sure it // doesn't go below the padding and border amount. node->setLayoutMeasuredDimension( @@ -2276,7 +2270,7 @@ static void calculateLayoutImpl( dimension(crossAxis)); } else if ( - measureModeCrossDim == MeasureMode::AtMost && + sizingModeCrossDim == SizingMode::FitContent && node->getStyle().overflow() == Overflow::Scroll) { node->setLayoutMeasuredDimension( yoga::maxOrDefined( @@ -2301,7 +2295,7 @@ static void calculateLayoutImpl( if (child->getStyle().positionType() != PositionType::Absolute) { child->setLayoutPosition( node->getLayout().measuredDimension(dimension(crossAxis)) - - child->getLayout().position[flexStartEdge(crossAxis)] - + child->getLayout().position(flexStartEdge(crossAxis)) - child->getLayout().measuredDimension(dimension(crossAxis)), flexStartEdge(crossAxis)); } @@ -2325,7 +2319,7 @@ static void calculateLayoutImpl( absolutePercentageAgainstPaddingEdge ? node->getLayout().measuredDimension(Dimension::Width) : availableInnerWidth, - isMainAxisRow ? measureModeMainDim : measureModeCrossDim, + isMainAxisRow ? sizingModeMainDim : sizingModeCrossDim, absolutePercentageAgainstPaddingEdge ? node->getLayout().measuredDimension(Dimension::Height) : availableInnerHeight, @@ -2375,15 +2369,15 @@ static const char* spacerWithLength(const unsigned long level) { } } -static const char* measureModeName( - const MeasureMode mode, +static const char* sizingModeName( + const SizingMode mode, const bool performLayout) { switch (mode) { - case MeasureMode::Undefined: + case SizingMode::MaxContent: return performLayout ? "LAY_UNDEFINED" : "UNDEFINED"; - case MeasureMode::Exactly: + case SizingMode::StretchFit: return performLayout ? "LAY_EXACTLY" : "EXACTLY"; - case MeasureMode::AtMost: + case SizingMode::FitContent: return performLayout ? "LAY_AT_MOST" : "AT_MOST"; } return ""; @@ -2402,8 +2396,8 @@ bool calculateLayoutInternal( const float availableWidth, const float availableHeight, const Direction ownerDirection, - const MeasureMode widthMeasureMode, - const MeasureMode heightMeasureMode, + const SizingMode widthSizingMode, + const SizingMode heightSizingMode, const float ownerWidth, const float ownerHeight, const bool performLayout, @@ -2424,8 +2418,8 @@ bool calculateLayoutInternal( layout->nextCachedMeasurementsIndex = 0; layout->cachedLayout.availableWidth = -1; layout->cachedLayout.availableHeight = -1; - layout->cachedLayout.widthMeasureMode = MeasureMode::Undefined; - layout->cachedLayout.heightMeasureMode = MeasureMode::Undefined; + layout->cachedLayout.widthSizingMode = SizingMode::MaxContent; + layout->cachedLayout.heightSizingMode = SizingMode::MaxContent; layout->cachedLayout.computedWidth = -1; layout->cachedLayout.computedHeight = -1; } @@ -2448,13 +2442,13 @@ bool calculateLayoutInternal( // First, try to use the layout cache. if (canUseCachedMeasurement( - widthMeasureMode, + widthSizingMode, availableWidth, - heightMeasureMode, + heightSizingMode, availableHeight, - layout->cachedLayout.widthMeasureMode, + layout->cachedLayout.widthSizingMode, layout->cachedLayout.availableWidth, - layout->cachedLayout.heightMeasureMode, + layout->cachedLayout.heightSizingMode, layout->cachedLayout.availableHeight, layout->cachedLayout.computedWidth, layout->cachedLayout.computedHeight, @@ -2466,13 +2460,13 @@ bool calculateLayoutInternal( // Try to use the measurement cache. for (size_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) { if (canUseCachedMeasurement( - widthMeasureMode, + widthSizingMode, availableWidth, - heightMeasureMode, + heightSizingMode, availableHeight, - layout->cachedMeasurements[i].widthMeasureMode, + layout->cachedMeasurements[i].widthSizingMode, layout->cachedMeasurements[i].availableWidth, - layout->cachedMeasurements[i].heightMeasureMode, + layout->cachedMeasurements[i].heightSizingMode, layout->cachedMeasurements[i].availableHeight, layout->cachedMeasurements[i].computedWidth, layout->cachedMeasurements[i].computedHeight, @@ -2489,8 +2483,8 @@ bool calculateLayoutInternal( layout->cachedLayout.availableWidth, availableWidth) && yoga::inexactEquals( layout->cachedLayout.availableHeight, availableHeight) && - layout->cachedLayout.widthMeasureMode == widthMeasureMode && - layout->cachedLayout.heightMeasureMode == heightMeasureMode) { + layout->cachedLayout.widthSizingMode == widthSizingMode && + layout->cachedLayout.heightSizingMode == heightSizingMode) { cachedResults = &layout->cachedLayout; } } else { @@ -2499,9 +2493,8 @@ bool calculateLayoutInternal( layout->cachedMeasurements[i].availableWidth, availableWidth) && yoga::inexactEquals( layout->cachedMeasurements[i].availableHeight, availableHeight) && - layout->cachedMeasurements[i].widthMeasureMode == widthMeasureMode && - layout->cachedMeasurements[i].heightMeasureMode == - heightMeasureMode) { + layout->cachedMeasurements[i].widthSizingMode == widthSizingMode && + layout->cachedMeasurements[i].heightSizingMode == heightSizingMode) { cachedResults = &layout->cachedMeasurements[i]; break; } @@ -2529,8 +2522,8 @@ bool calculateLayoutInternal( node, LogLevel::Verbose, "wm: %s, hm: %s, aw: %f ah: %f => d: (%f, %f) %s\n", - measureModeName(widthMeasureMode, performLayout), - measureModeName(heightMeasureMode, performLayout), + sizingModeName(widthSizingMode, performLayout), + sizingModeName(heightSizingMode, performLayout), availableWidth, availableHeight, cachedResults->computedWidth, @@ -2551,8 +2544,8 @@ bool calculateLayoutInternal( node, LogLevel::Verbose, "wm: %s, hm: %s, aw: %f ah: %f %s\n", - measureModeName(widthMeasureMode, performLayout), - measureModeName(heightMeasureMode, performLayout), + sizingModeName(widthSizingMode, performLayout), + sizingModeName(heightSizingMode, performLayout), availableWidth, availableHeight, LayoutPassReasonToString(reason)); @@ -2563,8 +2556,8 @@ bool calculateLayoutInternal( availableWidth, availableHeight, ownerDirection, - widthMeasureMode, - heightMeasureMode, + widthSizingMode, + heightSizingMode, ownerWidth, ownerHeight, performLayout, @@ -2586,8 +2579,8 @@ bool calculateLayoutInternal( node, LogLevel::Verbose, "wm: %s, hm: %s, d: (%f, %f) %s\n", - measureModeName(widthMeasureMode, performLayout), - measureModeName(heightMeasureMode, performLayout), + sizingModeName(widthSizingMode, performLayout), + sizingModeName(heightSizingMode, performLayout), layout->measuredDimension(Dimension::Width), layout->measuredDimension(Dimension::Height), LayoutPassReasonToString(reason)); @@ -2621,8 +2614,8 @@ bool calculateLayoutInternal( newCacheEntry->availableWidth = availableWidth; newCacheEntry->availableHeight = availableHeight; - newCacheEntry->widthMeasureMode = widthMeasureMode; - newCacheEntry->heightMeasureMode = heightMeasureMode; + newCacheEntry->widthSizingMode = widthSizingMode; + newCacheEntry->heightSizingMode = heightSizingMode; newCacheEntry->computedWidth = layout->measuredDimension(Dimension::Width); newCacheEntry->computedHeight = @@ -2672,7 +2665,7 @@ void calculateLayout( gCurrentGenerationCount.fetch_add(1, std::memory_order_relaxed); node->resolveDimension(); float width = YGUndefined; - MeasureMode widthMeasureMode = MeasureMode::Undefined; + SizingMode widthSizingMode = SizingMode::MaxContent; const auto& style = node->getStyle(); if (styleDefinesDimension(node, FlexDirection::Row, ownerWidth)) { width = @@ -2681,21 +2674,21 @@ void calculateLayout( ownerWidth) .unwrap() + node->getMarginForAxis(FlexDirection::Row, ownerWidth)); - widthMeasureMode = MeasureMode::Exactly; + widthSizingMode = SizingMode::StretchFit; } else if (yoga::resolveValue( style.maxDimension(Dimension::Width), ownerWidth) .isDefined()) { width = yoga::resolveValue(style.maxDimension(Dimension::Width), ownerWidth) .unwrap(); - widthMeasureMode = MeasureMode::AtMost; + widthSizingMode = SizingMode::FitContent; } else { width = ownerWidth; - widthMeasureMode = yoga::isUndefined(width) ? MeasureMode::Undefined - : MeasureMode::Exactly; + widthSizingMode = yoga::isUndefined(width) ? SizingMode::MaxContent + : SizingMode::StretchFit; } float height = YGUndefined; - MeasureMode heightMeasureMode = MeasureMode::Undefined; + SizingMode heightSizingMode = SizingMode::MaxContent; if (styleDefinesDimension(node, FlexDirection::Column, ownerHeight)) { height = (yoga::resolveValue( @@ -2703,26 +2696,26 @@ void calculateLayout( ownerHeight) .unwrap() + node->getMarginForAxis(FlexDirection::Column, ownerWidth)); - heightMeasureMode = MeasureMode::Exactly; + heightSizingMode = SizingMode::StretchFit; } else if (yoga::resolveValue( style.maxDimension(Dimension::Height), ownerHeight) .isDefined()) { height = yoga::resolveValue(style.maxDimension(Dimension::Height), ownerHeight) .unwrap(); - heightMeasureMode = MeasureMode::AtMost; + heightSizingMode = SizingMode::FitContent; } else { height = ownerHeight; - heightMeasureMode = yoga::isUndefined(height) ? MeasureMode::Undefined - : MeasureMode::Exactly; + heightSizingMode = yoga::isUndefined(height) ? SizingMode::MaxContent + : SizingMode::StretchFit; } if (calculateLayoutInternal( node, width, height, ownerDirection, - widthMeasureMode, - heightMeasureMode, + widthSizingMode, + heightSizingMode, ownerWidth, ownerHeight, true, diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/FlexDirection.h b/packages/react-native/ReactCommon/yoga/yoga/algorithm/FlexDirection.h index 3770783b7e7d71..5bc5880a4dd886 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/FlexDirection.h +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/FlexDirection.h @@ -11,6 +11,8 @@ #include #include +#include +#include #include namespace facebook::yoga { @@ -47,80 +49,80 @@ inline FlexDirection resolveCrossDirection( : FlexDirection::Column; } -inline YGEdge flexStartEdge(const FlexDirection flexDirection) { +inline Edge flexStartEdge(const FlexDirection flexDirection) { switch (flexDirection) { case FlexDirection::Column: - return YGEdgeTop; + return Edge::Top; case FlexDirection::ColumnReverse: - return YGEdgeBottom; + return Edge::Bottom; case FlexDirection::Row: - return YGEdgeLeft; + return Edge::Left; case FlexDirection::RowReverse: - return YGEdgeRight; + return Edge::Right; } fatalWithMessage("Invalid FlexDirection"); } -inline YGEdge flexEndEdge(const FlexDirection flexDirection) { +inline Edge flexEndEdge(const FlexDirection flexDirection) { switch (flexDirection) { case FlexDirection::Column: - return YGEdgeBottom; + return Edge::Bottom; case FlexDirection::ColumnReverse: - return YGEdgeTop; + return Edge::Top; case FlexDirection::Row: - return YGEdgeRight; + return Edge::Right; case FlexDirection::RowReverse: - return YGEdgeLeft; + return Edge::Left; } fatalWithMessage("Invalid FlexDirection"); } -inline YGEdge inlineStartEdge( +inline Edge inlineStartEdge( const FlexDirection flexDirection, const Direction direction) { if (isRow(flexDirection)) { - return direction == Direction::RTL ? YGEdgeRight : YGEdgeLeft; + return direction == Direction::RTL ? Edge::Right : Edge::Left; } - return YGEdgeTop; + return Edge::Top; } -inline YGEdge inlineEndEdge( +inline Edge inlineEndEdge( const FlexDirection flexDirection, const Direction direction) { if (isRow(flexDirection)) { - return direction == Direction::RTL ? YGEdgeLeft : YGEdgeRight; + return direction == Direction::RTL ? Edge::Left : Edge::Right; } - return YGEdgeBottom; + return Edge::Bottom; } /** - * The physical edges that YGEdgeStart and YGEdgeEnd correspond to (e.g. + * The physical edges that Edge::Start and Edge::End correspond to (e.g. * left/right) are soley dependent on the direction. However, there are cases * where we want the flex start/end edge (i.e. which edge is the start/end * for laying out flex items), which can be distinct from the corresponding * inline edge. In these cases we need to know which "relative edge" - * (YGEdgeStart/YGEdgeEnd) corresponds to the said flex start/end edge as these + * (Edge::Start/Edge::End) corresponds to the said flex start/end edge as these * relative edges can be used instead of physical ones when defining certain * attributes like border or padding. */ -inline YGEdge flexStartRelativeEdge( +inline Edge flexStartRelativeEdge( FlexDirection flexDirection, Direction direction) { - const YGEdge leadLayoutEdge = inlineStartEdge(flexDirection, direction); - const YGEdge leadFlexItemEdge = flexStartEdge(flexDirection); - return leadLayoutEdge == leadFlexItemEdge ? YGEdgeStart : YGEdgeEnd; + const Edge leadLayoutEdge = inlineStartEdge(flexDirection, direction); + const Edge leadFlexItemEdge = flexStartEdge(flexDirection); + return leadLayoutEdge == leadFlexItemEdge ? Edge::Start : Edge::End; } -inline YGEdge flexEndRelativeEdge( +inline Edge flexEndRelativeEdge( FlexDirection flexDirection, Direction direction) { - const YGEdge trailLayoutEdge = inlineEndEdge(flexDirection, direction); - const YGEdge trailFlexItemEdge = flexEndEdge(flexDirection); - return trailLayoutEdge == trailFlexItemEdge ? YGEdgeEnd : YGEdgeStart; + const Edge trailLayoutEdge = inlineEndEdge(flexDirection, direction); + const Edge trailFlexItemEdge = flexEndEdge(flexDirection); + return trailLayoutEdge == trailFlexItemEdge ? Edge::End : Edge::Start; } inline Dimension dimension(const FlexDirection flexDirection) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/PixelGrid.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/PixelGrid.cpp index 5e44c2cc8d40c6..b84cd7db090671 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/PixelGrid.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/PixelGrid.cpp @@ -68,8 +68,8 @@ void roundLayoutResultsToPixelGrid( const double absoluteTop) { const auto pointScaleFactor = node->getConfig()->getPointScaleFactor(); - const double nodeLeft = node->getLayout().position[YGEdgeLeft]; - const double nodeTop = node->getLayout().position[YGEdgeTop]; + const double nodeLeft = node->getLayout().position(Edge::Left); + const double nodeTop = node->getLayout().position(Edge::Top); const double nodeWidth = node->getLayout().dimension(Dimension::Width); const double nodeHeight = node->getLayout().dimension(Dimension::Height); @@ -87,11 +87,11 @@ void roundLayoutResultsToPixelGrid( node->setLayoutPosition( roundValueToPixelGrid(nodeLeft, pointScaleFactor, false, textRounding), - YGEdgeLeft); + Edge::Left); node->setLayoutPosition( roundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding), - YGEdgeTop); + Edge::Top); // We multiply dimension by scale factor and if the result is close to the // whole number, we don't have any fraction To verify if the result is close diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/ResolveValue.h b/packages/react-native/ReactCommon/yoga/yoga/algorithm/ResolveValue.h index 4e03d0c50d4d9a..a2d650b237a0cb 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/ResolveValue.h +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/ResolveValue.h @@ -10,7 +10,7 @@ #include #include -#include +#include namespace facebook::yoga { @@ -25,7 +25,7 @@ inline FloatOptional resolveValue(const YGValue value, const float ownerSize) { } } -inline FloatOptional resolveValue(CompactValue value, float ownerSize) { +inline FloatOptional resolveValue(Style::Length value, float ownerSize) { return resolveValue((YGValue)value, ownerSize); } diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/SizingMode.h b/packages/react-native/ReactCommon/yoga/yoga/algorithm/SizingMode.h new file mode 100644 index 00000000000000..bd725df13ac68b --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/SizingMode.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook::yoga { + +/** + * Corresponds to a CSS auto box sizes. Missing "min-content", as Yoga does not + * current support automatic minimum sizes. + * https://www.w3.org/TR/css-sizing-3/#auto-box-sizes + * https://www.w3.org/TR/css-flexbox-1/#min-size-auto + */ +enum class SizingMode { + /** + * The size a box would take if its outer size filled the available space in + * the given axis; in other words, the stretch fit into the available space, + * if that is definite. Undefined if the available space is indefinite. + */ + StretchFit, + + /** + * A box’s “ideal” size in a given axis when given infinite available space. + * Usually this is the smallest size the box could take in that axis while + * still fitting around its contents, i.e. minimizing unfilled space while + * avoiding overflow. + */ + MaxContent, + + /** + * If the available space in a given axis is definite, equal to + * clamp(min-content size, stretch-fit size, max-content size) (i.e. + * max(min-content size, min(max-content size, stretch-fit size))). When + * sizing under a min-content constraint, equal to the min-content size. + * Otherwise, equal to the max-content size in that axis. + */ + FitContent, +}; + +inline MeasureMode measureMode(SizingMode mode) { + switch (mode) { + case SizingMode::StretchFit: + return MeasureMode::Exactly; + case SizingMode::MaxContent: + return MeasureMode::Undefined; + case SizingMode::FitContent: + return MeasureMode::AtMost; + } + + fatalWithMessage("Invalid SizingMode"); +} + +inline SizingMode sizingMode(MeasureMode mode) { + switch (mode) { + case MeasureMode::Exactly: + return SizingMode::StretchFit; + case MeasureMode::Undefined: + return SizingMode::MaxContent; + case MeasureMode::AtMost: + return SizingMode::FitContent; + } + + fatalWithMessage("Invalid MeasureMode"); +} + +} // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/bits/NumericBitfield.h b/packages/react-native/ReactCommon/yoga/yoga/bits/NumericBitfield.h deleted file mode 100644 index d6102409b2b787..00000000000000 --- a/packages/react-native/ReactCommon/yoga/yoga/bits/NumericBitfield.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include - -namespace facebook::yoga::details { - -constexpr uint8_t log2ceilFn(uint8_t n) { - return n < 1 ? 0 : (1 + log2ceilFn(n / 2)); -} - -constexpr uint32_t mask(uint8_t bitWidth, uint8_t index) { - return ((1u << bitWidth) - 1u) << index; -} - -} // namespace facebook::yoga::details - -namespace facebook::yoga { - -// The number of bits necessary to represent enums defined with YG_ENUM_SEQ_DECL -template < - typename Enum, - std::enable_if_t<(ordinalCount() > 0), bool> = true> -constexpr uint8_t minimumBitCount() { - return details::log2ceilFn(static_cast(ordinalCount() - 1)); -} - -template -constexpr Enum getEnumData(uint32_t flags, uint8_t index) { - return static_cast( - (flags & details::mask(minimumBitCount(), index)) >> index); -} - -template -void setEnumData(uint32_t& flags, uint8_t index, Value newValue) { - flags = - (flags & - ~static_cast(details::mask(minimumBitCount(), index))) | - ((static_cast(newValue) << index) & - (details::mask(minimumBitCount(), index))); -} - -constexpr bool getBooleanData(uint32_t flags, uint8_t index) { - return (flags >> index) & 1; -} - -inline void setBooleanData(uint32_t& flags, uint8_t index, bool value) { - if (value) { - flags |= 1 << index; - } else { - flags &= ~(1 << index); - } -} - -} // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/debug/AssertFatal.cpp b/packages/react-native/ReactCommon/yoga/yoga/debug/AssertFatal.cpp index 2388a744539dbe..e43ce2a254ee23 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/debug/AssertFatal.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/debug/AssertFatal.cpp @@ -7,8 +7,10 @@ #include +#include #include #include +#include namespace facebook::yoga { diff --git a/packages/react-native/ReactCommon/yoga/yoga/debug/AssertFatal.h b/packages/react-native/ReactCommon/yoga/yoga/debug/AssertFatal.h index 929ff1792d0d8f..bbd8ad19eabbf0 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/debug/AssertFatal.h +++ b/packages/react-native/ReactCommon/yoga/yoga/debug/AssertFatal.h @@ -8,11 +8,12 @@ #pragma once #include -#include -#include namespace facebook::yoga { +class Node; +class Config; + [[noreturn]] void fatalWithMessage(const char* message); void assertFatal(bool condition, const char* message); diff --git a/packages/react-native/ReactCommon/yoga/yoga/debug/NodeToString.cpp b/packages/react-native/ReactCommon/yoga/yoga/debug/NodeToString.cpp index a2bf467bede115..18e8aeec659b50 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/debug/NodeToString.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/debug/NodeToString.cpp @@ -9,8 +9,6 @@ #include -#include - #include #include #include @@ -23,12 +21,6 @@ static void indent(std::string& base, uint32_t level) { } } -static bool areFourValuesEqual(const Style::Edges& four) { - return yoga::inexactEquals(four[0], four[1]) && - yoga::inexactEquals(four[0], four[2]) && - yoga::inexactEquals(four[0], four[3]); -} - static void appendFormattedString(std::string& str, const char* fmt, ...) { va_list args; va_start(args, fmt); @@ -86,33 +78,15 @@ static void appendNumberIfNotZero( } } -static void appendEdges( - std::string& base, - const std::string& key, - const Style::Edges& edges) { - if (areFourValuesEqual(edges)) { - auto edgeValue = yoga::Node::computeEdgeValueForColumn(edges, YGEdgeLeft); - appendNumberIfNotUndefined(base, key, edgeValue); - } else { - for (int edge = YGEdgeLeft; edge != YGEdgeAll; ++edge) { - std::string str = key + "-" + YGEdgeToString(static_cast(edge)); - appendNumberIfNotZero(base, str, edges[static_cast(edge)]); - } +template +static void +appendEdges(std::string& base, const std::string& key, const Style& style) { + for (auto edge : ordinals()) { + std::string str = key + "-" + toString(edge); + appendNumberIfNotZero(base, str, (style.*Field)(edge)); } } -static void appendEdgeIfNotUndefined( - std::string& base, - const std::string& str, - const Style::Edges& edges, - const YGEdge edge) { - // TODO: this doesn't take RTL / YGEdgeStart / YGEdgeEnd into account - auto value = (edge == YGEdgeLeft || edge == YGEdgeRight) - ? yoga::Node::computeEdgeValueForRow(edges, edge, edge) - : yoga::Node::computeEdgeValueForColumn(edges, edge); - appendNumberIfNotUndefined(base, str, value); -} - void nodeToString( std::string& str, const yoga::Node* node, @@ -128,9 +102,9 @@ void nodeToString( appendFormattedString( str, "height: %g; ", node->getLayout().dimension(Dimension::Height)); appendFormattedString( - str, "top: %g; ", node->getLayout().position[YGEdgeTop]); + str, "top: %g; ", node->getLayout().position(Edge::Top)); appendFormattedString( - str, "left: %g;", node->getLayout().position[YGEdgeLeft]); + str, "left: %g;", node->getLayout().position(Edge::Left)); appendFormattedString(str, "\" "); } @@ -173,9 +147,9 @@ void nodeToString( if (style.display() != yoga::Node{}.getStyle().display()) { appendFormattedString(str, "display: %s; ", toString(style.display())); } - appendEdges(str, "margin", style.margin()); - appendEdges(str, "padding", style.padding()); - appendEdges(str, "border", style.border()); + appendEdges<&Style::margin>(str, "margin", style); + appendEdges<&Style::padding>(str, "padding", style); + appendEdges<&Style::border>(str, "border", style); if (style.gap(Gutter::All).isDefined()) { appendNumberIfNotUndefined(str, "gap", style.gap(Gutter::All)); @@ -200,10 +174,7 @@ void nodeToString( str, "position: %s; ", toString(style.positionType())); } - appendEdgeIfNotUndefined(str, "left", style.position(), YGEdgeLeft); - appendEdgeIfNotUndefined(str, "right", style.position(), YGEdgeRight); - appendEdgeIfNotUndefined(str, "top", style.position(), YGEdgeTop); - appendEdgeIfNotUndefined(str, "bottom", style.position(), YGEdgeBottom); + appendEdges<&Style::position>(str, "position", style); appendFormattedString(str, "\" "); if (node->hasMeasureFunc()) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/enums/Errata.h b/packages/react-native/ReactCommon/yoga/yoga/enums/Errata.h index 6a085bf58da825..134f5fffc012fe 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/enums/Errata.h +++ b/packages/react-native/ReactCommon/yoga/yoga/enums/Errata.h @@ -26,16 +26,6 @@ enum class Errata : uint32_t { YG_DEFINE_ENUM_FLAG_OPERATORS(Errata) -template <> -constexpr inline int32_t ordinalCount() { - return 6; -} - -template <> -constexpr inline int32_t bitCount() { - return 3; -} - constexpr inline Errata scopedEnum(YGErrata unscoped) { return static_cast(unscoped); } diff --git a/packages/react-native/ReactCommon/yoga/yoga/enums/PrintOptions.h b/packages/react-native/ReactCommon/yoga/yoga/enums/PrintOptions.h index c61fbc6383a279..90d0043c74a4dd 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/enums/PrintOptions.h +++ b/packages/react-native/ReactCommon/yoga/yoga/enums/PrintOptions.h @@ -23,16 +23,6 @@ enum class PrintOptions : uint32_t { YG_DEFINE_ENUM_FLAG_OPERATORS(PrintOptions) -template <> -constexpr inline int32_t ordinalCount() { - return 3; -} - -template <> -constexpr inline int32_t bitCount() { - return 2; -} - constexpr inline PrintOptions scopedEnum(YGPrintOptions unscoped) { return static_cast(unscoped); } diff --git a/packages/react-native/ReactCommon/yoga/yoga/enums/YogaEnums.h b/packages/react-native/ReactCommon/yoga/yoga/enums/YogaEnums.h index 7cbf94b72f8601..a3e1191de11eae 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/enums/YogaEnums.h +++ b/packages/react-native/ReactCommon/yoga/yoga/enums/YogaEnums.h @@ -7,6 +7,7 @@ #pragma once +#include #include namespace facebook::yoga { @@ -14,13 +15,52 @@ namespace facebook::yoga { template constexpr inline int32_t ordinalCount(); +/** + * Count of bits needed to represent every ordinal + */ template constexpr inline int32_t bitCount(); -// Polyfill of C++ 23 to_underlying() -// https://en.cppreference.com/w/cpp/utility/to_underlying +/** + * Polyfill of C++ 23 to_underlying() + * https://en.cppreference.com/w/cpp/utility/to_underlying + */ constexpr auto to_underlying(auto e) noexcept { return static_cast>(e); } +/** + * Convenience function to iterate through every value in a Yoga enum as part of + * a range-based for loop. + */ +template +auto ordinals() { + struct Iterator { + EnumT e{}; + + EnumT operator*() const { + return e; + } + + Iterator& operator++() { + e = static_cast(to_underlying(e) + 1); + return *this; + } + + bool operator==(const Iterator& other) const = default; + bool operator!=(const Iterator& other) const = default; + }; + + struct Range { + Iterator begin() const { + return Iterator{}; + } + Iterator end() const { + return Iterator{static_cast(ordinalCount())}; + } + }; + + return Range{}; +} + } // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/module.modulemap b/packages/react-native/ReactCommon/yoga/yoga/module.modulemap index 5a8aad8ff27dce..6a0f46030e8c56 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/module.modulemap +++ b/packages/react-native/ReactCommon/yoga/yoga/module.modulemap @@ -12,7 +12,7 @@ module yoga [system] { header "YGMacros.h" header "YGNode.h" header "YGNodeLayout.h" - header "YGNodeStye.h" + header "YGNodeStyle.h" header "YGPixelGrid.h" header "YGValue.h" header "Yoga.h" diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/CachedMeasurement.h b/packages/react-native/ReactCommon/yoga/yoga/node/CachedMeasurement.h index 4d2c22260075dc..9c76280acf74e1 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/CachedMeasurement.h +++ b/packages/react-native/ReactCommon/yoga/yoga/node/CachedMeasurement.h @@ -11,7 +11,7 @@ #include -#include +#include #include namespace facebook::yoga { @@ -19,15 +19,15 @@ namespace facebook::yoga { struct CachedMeasurement { float availableWidth{-1}; float availableHeight{-1}; - MeasureMode widthMeasureMode{MeasureMode::Undefined}; - MeasureMode heightMeasureMode{MeasureMode::Undefined}; + SizingMode widthSizingMode{SizingMode::MaxContent}; + SizingMode heightSizingMode{SizingMode::MaxContent}; float computedWidth{-1}; float computedHeight{-1}; bool operator==(CachedMeasurement measurement) const { - bool isEqual = widthMeasureMode == measurement.widthMeasureMode && - heightMeasureMode == measurement.heightMeasureMode; + bool isEqual = widthSizingMode == measurement.widthSizingMode && + heightSizingMode == measurement.heightSizingMode; if (!yoga::isUndefined(availableWidth) || !yoga::isUndefined(measurement.availableWidth)) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.cpp b/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.cpp index d050bfdc73fec6..fd70870e65b3a7 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.cpp @@ -13,11 +13,11 @@ namespace facebook::yoga { bool LayoutResults::operator==(LayoutResults layout) const { - bool isEqual = yoga::inexactEquals(position, layout.position) && + bool isEqual = yoga::inexactEquals(position_, layout.position_) && yoga::inexactEquals(dimensions_, layout.dimensions_) && - yoga::inexactEquals(margin, layout.margin) && - yoga::inexactEquals(border, layout.border) && - yoga::inexactEquals(padding, layout.padding) && + yoga::inexactEquals(margin_, layout.margin_) && + yoga::inexactEquals(border_, layout.border_) && + yoga::inexactEquals(padding_, layout.padding_) && direction() == layout.direction() && hadOverflow() == layout.hadOverflow() && lastOwnerDirection == layout.lastOwnerDirection && diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.h b/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.h index 8b324e6454bf38..819ec1e487d989 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.h +++ b/packages/react-native/ReactCommon/yoga/yoga/node/LayoutResults.h @@ -9,9 +9,10 @@ #include -#include +#include #include #include +#include #include #include @@ -22,19 +23,6 @@ struct LayoutResults { // 98% of analyzed layouts require less than 8 entries. static constexpr int32_t MaxCachedMeasurements = 8; - std::array position = {}; - std::array margin = {}; - std::array border = {}; - std::array padding = {}; - - private: - Direction direction_ : bitCount() = Direction::Inherit; - bool hadOverflow_ : 1 = false; - - std::array dimensions_ = {{YGUndefined, YGUndefined}}; - std::array measuredDimensions_ = {{YGUndefined, YGUndefined}}; - - public: uint32_t computedFlexBasisGeneration = 0; FloatOptional computedFlexBasis = {}; @@ -80,10 +68,66 @@ struct LayoutResults { measuredDimensions_[yoga::to_underlying(axis)] = dimension; } + float position(Edge cardinalEdge) const { + assertCardinalEdge(cardinalEdge); + return position_[yoga::to_underlying(cardinalEdge)]; + } + + void setPosition(Edge cardinalEdge, float dimension) { + assertCardinalEdge(cardinalEdge); + position_[yoga::to_underlying(cardinalEdge)] = dimension; + } + + float margin(Edge cardinalEdge) const { + assertCardinalEdge(cardinalEdge); + return margin_[yoga::to_underlying(cardinalEdge)]; + } + + void setMargin(Edge cardinalEdge, float dimension) { + assertCardinalEdge(cardinalEdge); + margin_[yoga::to_underlying(cardinalEdge)] = dimension; + } + + float border(Edge cardinalEdge) const { + assertCardinalEdge(cardinalEdge); + return border_[yoga::to_underlying(cardinalEdge)]; + } + + void setBorder(Edge cardinalEdge, float dimension) { + assertCardinalEdge(cardinalEdge); + border_[yoga::to_underlying(cardinalEdge)] = dimension; + } + + float padding(Edge cardinalEdge) const { + assertCardinalEdge(cardinalEdge); + return padding_[yoga::to_underlying(cardinalEdge)]; + } + + void setPadding(Edge cardinalEdge, float dimension) { + assertCardinalEdge(cardinalEdge); + padding_[yoga::to_underlying(cardinalEdge)] = dimension; + } + bool operator==(LayoutResults layout) const; bool operator!=(LayoutResults layout) const { return !(*this == layout); } + + private: + static inline void assertCardinalEdge(Edge edge) { + assertFatal( + static_cast(edge) <= 3, "Edge must be top/left/bottom/right"); + } + + Direction direction_ : bitCount() = Direction::Inherit; + bool hadOverflow_ : 1 = false; + + std::array dimensions_ = {{YGUndefined, YGUndefined}}; + std::array measuredDimensions_ = {{YGUndefined, YGUndefined}}; + std::array position_ = {}; + std::array margin_ = {}; + std::array border_ = {}; + std::array padding_ = {}; }; } // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp b/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp index e69c96f5aeddee..faf812e8cf1949 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp @@ -56,34 +56,33 @@ void Node::print() { } } -CompactValue Node::computeEdgeValueForRow( - const Style::Edges& edges, - YGEdge rowEdge, - YGEdge edge) { - if (edges[rowEdge].isDefined()) { - return edges[rowEdge]; - } else if (edges[edge].isDefined()) { - return edges[edge]; - } else if (edges[YGEdgeHorizontal].isDefined()) { - return edges[YGEdgeHorizontal]; +// TODO: Edge value resolution should be moved to `yoga::Style` +template +Style::Length Node::computeEdgeValueForRow(Edge rowEdge, Edge edge) const { + if ((style_.*Field)(rowEdge).isDefined()) { + return (style_.*Field)(rowEdge); + } else if ((style_.*Field)(edge).isDefined()) { + return (style_.*Field)(edge); + } else if ((style_.*Field)(Edge::Horizontal).isDefined()) { + return (style_.*Field)(Edge::Horizontal); } else { - return edges[YGEdgeAll]; + return (style_.*Field)(Edge::All); } } -CompactValue Node::computeEdgeValueForColumn( - const Style::Edges& edges, - YGEdge edge) { - if (edges[edge].isDefined()) { - return edges[edge]; - } else if (edges[YGEdgeVertical].isDefined()) { - return edges[YGEdgeVertical]; +// TODO: Edge value resolution should be moved to `yoga::Style` +template +Style::Length Node::computeEdgeValueForColumn(Edge edge) const { + if ((style_.*Field)(edge).isDefined()) { + return (style_.*Field)(edge); + } else if ((style_.*Field)(Edge::Vertical).isDefined()) { + return (style_.*Field)(Edge::Vertical); } else { - return edges[YGEdgeAll]; + return (style_.*Field)(Edge::All); } } -YGEdge Node::getInlineStartEdgeUsingErrata( +Edge Node::getInlineStartEdgeUsingErrata( FlexDirection flexDirection, Direction direction) const { return hasErrata(Errata::StartingEndingEdgeFromFlexDirection) @@ -91,7 +90,7 @@ YGEdge Node::getInlineStartEdgeUsingErrata( : inlineStartEdge(flexDirection, direction); } -YGEdge Node::getInlineEndEdgeUsingErrata( +Edge Node::getInlineEndEdgeUsingErrata( FlexDirection flexDirection, Direction direction) const { return hasErrata(Errata::StartingEndingEdgeFromFlexDirection) @@ -100,48 +99,48 @@ YGEdge Node::getInlineEndEdgeUsingErrata( } bool Node::isFlexStartPositionDefined(FlexDirection axis) const { - const YGEdge startEdge = flexStartEdge(axis); + const Edge startEdge = flexStartEdge(axis); auto leadingPosition = isRow(axis) - ? computeEdgeValueForRow(style_.position(), YGEdgeStart, startEdge) - : computeEdgeValueForColumn(style_.position(), startEdge); + ? computeEdgeValueForRow<&Style::position>(Edge::Start, startEdge) + : computeEdgeValueForColumn<&Style::position>(startEdge); return leadingPosition.isDefined(); } bool Node::isInlineStartPositionDefined(FlexDirection axis, Direction direction) const { - const YGEdge startEdge = getInlineStartEdgeUsingErrata(axis, direction); + const Edge startEdge = getInlineStartEdgeUsingErrata(axis, direction); auto leadingPosition = isRow(axis) - ? computeEdgeValueForRow(style_.position(), YGEdgeStart, startEdge) - : computeEdgeValueForColumn(style_.position(), startEdge); + ? computeEdgeValueForRow<&Style::position>(Edge::Start, startEdge) + : computeEdgeValueForColumn<&Style::position>(startEdge); return leadingPosition.isDefined(); } bool Node::isFlexEndPositionDefined(FlexDirection axis) const { - const YGEdge endEdge = flexEndEdge(axis); + const Edge endEdge = flexEndEdge(axis); auto trailingPosition = isRow(axis) - ? computeEdgeValueForRow(style_.position(), YGEdgeEnd, endEdge) - : computeEdgeValueForColumn(style_.position(), endEdge); + ? computeEdgeValueForRow<&Style::position>(Edge::End, endEdge) + : computeEdgeValueForColumn<&Style::position>(endEdge); return !trailingPosition.isUndefined(); } bool Node::isInlineEndPositionDefined(FlexDirection axis, Direction direction) const { - const YGEdge endEdge = getInlineEndEdgeUsingErrata(axis, direction); + const Edge endEdge = getInlineEndEdgeUsingErrata(axis, direction); auto trailingPosition = isRow(axis) - ? computeEdgeValueForRow(style_.position(), YGEdgeEnd, endEdge) - : computeEdgeValueForColumn(style_.position(), endEdge); + ? computeEdgeValueForRow<&Style::position>(Edge::End, endEdge) + : computeEdgeValueForColumn<&Style::position>(endEdge); return trailingPosition.isDefined(); } float Node::getFlexStartPosition(FlexDirection axis, float axisSize) const { - const YGEdge startEdge = flexStartEdge(axis); + const Edge startEdge = flexStartEdge(axis); auto leadingPosition = isRow(axis) - ? computeEdgeValueForRow(style_.position(), YGEdgeStart, startEdge) - : computeEdgeValueForColumn(style_.position(), startEdge); + ? computeEdgeValueForRow<&Style::position>(Edge::Start, startEdge) + : computeEdgeValueForColumn<&Style::position>(startEdge); return resolveValue(leadingPosition, axisSize).unwrapOrDefault(0.0f); } @@ -150,19 +149,19 @@ float Node::getInlineStartPosition( FlexDirection axis, Direction direction, float axisSize) const { - const YGEdge startEdge = getInlineStartEdgeUsingErrata(axis, direction); + const Edge startEdge = getInlineStartEdgeUsingErrata(axis, direction); auto leadingPosition = isRow(axis) - ? computeEdgeValueForRow(style_.position(), YGEdgeStart, startEdge) - : computeEdgeValueForColumn(style_.position(), startEdge); + ? computeEdgeValueForRow<&Style::position>(Edge::Start, startEdge) + : computeEdgeValueForColumn<&Style::position>(startEdge); return resolveValue(leadingPosition, axisSize).unwrapOrDefault(0.0f); } float Node::getFlexEndPosition(FlexDirection axis, float axisSize) const { - const YGEdge endEdge = flexEndEdge(axis); + const Edge endEdge = flexEndEdge(axis); auto trailingPosition = isRow(axis) - ? computeEdgeValueForRow(style_.position(), YGEdgeEnd, endEdge) - : computeEdgeValueForColumn(style_.position(), endEdge); + ? computeEdgeValueForRow<&Style::position>(Edge::End, endEdge) + : computeEdgeValueForColumn<&Style::position>(endEdge); return resolveValue(trailingPosition, axisSize).unwrapOrDefault(0.0f); } @@ -171,19 +170,19 @@ float Node::getInlineEndPosition( FlexDirection axis, Direction direction, float axisSize) const { - const YGEdge endEdge = getInlineEndEdgeUsingErrata(axis, direction); + const Edge endEdge = getInlineEndEdgeUsingErrata(axis, direction); auto trailingPosition = isRow(axis) - ? computeEdgeValueForRow(style_.position(), YGEdgeEnd, endEdge) - : computeEdgeValueForColumn(style_.position(), endEdge); + ? computeEdgeValueForRow<&Style::position>(Edge::End, endEdge) + : computeEdgeValueForColumn<&Style::position>(endEdge); return resolveValue(trailingPosition, axisSize).unwrapOrDefault(0.0f); } float Node::getFlexStartMargin(FlexDirection axis, float widthSize) const { - const YGEdge startEdge = flexStartEdge(axis); + const Edge startEdge = flexStartEdge(axis); auto leadingMargin = isRow(axis) - ? computeEdgeValueForRow(style_.margin(), YGEdgeStart, startEdge) - : computeEdgeValueForColumn(style_.margin(), startEdge); + ? computeEdgeValueForRow<&Style::margin>(Edge::Start, startEdge) + : computeEdgeValueForColumn<&Style::margin>(startEdge); return resolveValue(leadingMargin, widthSize).unwrapOrDefault(0.0f); } @@ -192,19 +191,19 @@ float Node::getInlineStartMargin( FlexDirection axis, Direction direction, float widthSize) const { - const YGEdge startEdge = getInlineStartEdgeUsingErrata(axis, direction); + const Edge startEdge = getInlineStartEdgeUsingErrata(axis, direction); auto leadingMargin = isRow(axis) - ? computeEdgeValueForRow(style_.margin(), YGEdgeStart, startEdge) - : computeEdgeValueForColumn(style_.margin(), startEdge); + ? computeEdgeValueForRow<&Style::margin>(Edge::Start, startEdge) + : computeEdgeValueForColumn<&Style::margin>(startEdge); return resolveValue(leadingMargin, widthSize).unwrapOrDefault(0.0f); } float Node::getFlexEndMargin(FlexDirection axis, float widthSize) const { - const YGEdge endEdge = flexEndEdge(axis); + const Edge endEdge = flexEndEdge(axis); auto trailingMargin = isRow(axis) - ? computeEdgeValueForRow(style_.margin(), YGEdgeEnd, endEdge) - : computeEdgeValueForColumn(style_.margin(), endEdge); + ? computeEdgeValueForRow<&Style::margin>(Edge::End, endEdge) + : computeEdgeValueForColumn<&Style::margin>(endEdge); return resolveValue(trailingMargin, widthSize).unwrapOrDefault(0.0f); } @@ -213,50 +212,49 @@ float Node::getInlineEndMargin( FlexDirection axis, Direction direction, float widthSize) const { - const YGEdge endEdge = getInlineEndEdgeUsingErrata(axis, direction); + const Edge endEdge = getInlineEndEdgeUsingErrata(axis, direction); auto trailingMargin = isRow(axis) - ? computeEdgeValueForRow(style_.margin(), YGEdgeEnd, endEdge) - : computeEdgeValueForColumn(style_.margin(), endEdge); + ? computeEdgeValueForRow<&Style::margin>(Edge::End, endEdge) + : computeEdgeValueForColumn<&Style::margin>(endEdge); return resolveValue(trailingMargin, widthSize).unwrapOrDefault(0.0f); } float Node::getInlineStartBorder(FlexDirection axis, Direction direction) const { - const YGEdge startEdge = getInlineStartEdgeUsingErrata(axis, direction); + const Edge startEdge = getInlineStartEdgeUsingErrata(axis, direction); YGValue leadingBorder = isRow(axis) - ? computeEdgeValueForRow(style_.border(), YGEdgeStart, startEdge) - : computeEdgeValueForColumn(style_.border(), startEdge); + ? computeEdgeValueForRow<&Style::border>(Edge::Start, startEdge) + : computeEdgeValueForColumn<&Style::border>(startEdge); return maxOrDefined(leadingBorder.value, 0.0f); } float Node::getFlexStartBorder(FlexDirection axis, Direction direction) const { - const YGEdge leadRelativeFlexItemEdge = - flexStartRelativeEdge(axis, direction); + const Edge leadRelativeFlexItemEdge = flexStartRelativeEdge(axis, direction); YGValue leadingBorder = isRow(axis) - ? computeEdgeValueForRow( - style_.border(), leadRelativeFlexItemEdge, flexStartEdge(axis)) - : computeEdgeValueForColumn(style_.border(), flexStartEdge(axis)); + ? computeEdgeValueForRow<&Style::border>( + leadRelativeFlexItemEdge, flexStartEdge(axis)) + : computeEdgeValueForColumn<&Style::border>(flexStartEdge(axis)); return maxOrDefined(leadingBorder.value, 0.0f); } float Node::getInlineEndBorder(FlexDirection axis, Direction direction) const { - const YGEdge endEdge = getInlineEndEdgeUsingErrata(axis, direction); + const Edge endEdge = getInlineEndEdgeUsingErrata(axis, direction); YGValue trailingBorder = isRow(axis) - ? computeEdgeValueForRow(style_.border(), YGEdgeEnd, endEdge) - : computeEdgeValueForColumn(style_.border(), endEdge); + ? computeEdgeValueForRow<&Style::border>(Edge::End, endEdge) + : computeEdgeValueForColumn<&Style::border>(endEdge); return maxOrDefined(trailingBorder.value, 0.0f); } float Node::getFlexEndBorder(FlexDirection axis, Direction direction) const { - const YGEdge trailRelativeFlexItemEdge = flexEndRelativeEdge(axis, direction); + const Edge trailRelativeFlexItemEdge = flexEndRelativeEdge(axis, direction); YGValue trailingBorder = isRow(axis) - ? computeEdgeValueForRow( - style_.border(), trailRelativeFlexItemEdge, flexEndEdge(axis)) - : computeEdgeValueForColumn(style_.border(), flexEndEdge(axis)); + ? computeEdgeValueForRow<&Style::border>( + trailRelativeFlexItemEdge, flexEndEdge(axis)) + : computeEdgeValueForColumn<&Style::border>(flexEndEdge(axis)); return maxOrDefined(trailingBorder.value, 0.0f); } @@ -265,10 +263,10 @@ float Node::getInlineStartPadding( FlexDirection axis, Direction direction, float widthSize) const { - const YGEdge startEdge = getInlineStartEdgeUsingErrata(axis, direction); + const Edge startEdge = getInlineStartEdgeUsingErrata(axis, direction); auto leadingPadding = isRow(axis) - ? computeEdgeValueForRow(style_.padding(), YGEdgeStart, startEdge) - : computeEdgeValueForColumn(style_.padding(), startEdge); + ? computeEdgeValueForRow<&Style::padding>(Edge::Start, startEdge) + : computeEdgeValueForColumn<&Style::padding>(startEdge); return maxOrDefined(resolveValue(leadingPadding, widthSize).unwrap(), 0.0f); } @@ -277,12 +275,11 @@ float Node::getFlexStartPadding( FlexDirection axis, Direction direction, float widthSize) const { - const YGEdge leadRelativeFlexItemEdge = - flexStartRelativeEdge(axis, direction); + const Edge leadRelativeFlexItemEdge = flexStartRelativeEdge(axis, direction); auto leadingPadding = isRow(axis) - ? computeEdgeValueForRow( - style_.padding(), leadRelativeFlexItemEdge, flexStartEdge(axis)) - : computeEdgeValueForColumn(style_.padding(), flexStartEdge(axis)); + ? computeEdgeValueForRow<&Style::padding>( + leadRelativeFlexItemEdge, flexStartEdge(axis)) + : computeEdgeValueForColumn<&Style::padding>(flexStartEdge(axis)); return maxOrDefined(resolveValue(leadingPadding, widthSize).unwrap(), 0.0f); } @@ -291,10 +288,10 @@ float Node::getInlineEndPadding( FlexDirection axis, Direction direction, float widthSize) const { - const YGEdge endEdge = getInlineEndEdgeUsingErrata(axis, direction); + const Edge endEdge = getInlineEndEdgeUsingErrata(axis, direction); auto trailingPadding = isRow(axis) - ? computeEdgeValueForRow(style_.padding(), YGEdgeEnd, endEdge) - : computeEdgeValueForColumn(style_.padding(), endEdge); + ? computeEdgeValueForRow<&Style::padding>(Edge::End, endEdge) + : computeEdgeValueForColumn<&Style::padding>(endEdge); return maxOrDefined(resolveValue(trailingPadding, widthSize).unwrap(), 0.0f); } @@ -303,11 +300,11 @@ float Node::getFlexEndPadding( FlexDirection axis, Direction direction, float widthSize) const { - const YGEdge trailRelativeFlexItemEdge = flexEndRelativeEdge(axis, direction); + const Edge trailRelativeFlexItemEdge = flexEndRelativeEdge(axis, direction); auto trailingPadding = isRow(axis) - ? computeEdgeValueForRow( - style_.padding(), trailRelativeFlexItemEdge, flexEndEdge(axis)) - : computeEdgeValueForColumn(style_.padding(), flexEndEdge(axis)); + ? computeEdgeValueForRow<&Style::padding>( + trailRelativeFlexItemEdge, flexEndEdge(axis)) + : computeEdgeValueForColumn<&Style::padding>(flexEndEdge(axis)); return maxOrDefined(resolveValue(trailingPadding, widthSize).unwrap(), 0.0f); } @@ -447,25 +444,16 @@ void Node::setLayoutDirection(Direction direction) { layout_.setDirection(direction); } -void Node::setLayoutMargin(float margin, YGEdge edge) { - assertFatal( - edge < static_cast(layout_.margin.size()), - "Edge must be top/left/bottom/right"); - layout_.margin[edge] = margin; +void Node::setLayoutMargin(float margin, Edge edge) { + layout_.setMargin(edge, margin); } -void Node::setLayoutBorder(float border, YGEdge edge) { - assertFatal( - edge < static_cast(layout_.border.size()), - "Edge must be top/left/bottom/right"); - layout_.border[edge] = border; +void Node::setLayoutBorder(float border, Edge edge) { + layout_.setBorder(edge, border); } -void Node::setLayoutPadding(float padding, YGEdge edge) { - assertFatal( - edge < static_cast(layout_.padding.size()), - "Edge must be top/left/bottom/right"); - layout_.padding[edge] = padding; +void Node::setLayoutPadding(float padding, Edge edge) { + layout_.setPadding(edge, padding); } void Node::setLayoutLastOwnerDirection(Direction direction) { @@ -476,11 +464,8 @@ void Node::setLayoutComputedFlexBasis(const FloatOptional computedFlexBasis) { layout_.computedFlexBasis = computedFlexBasis; } -void Node::setLayoutPosition(float position, YGEdge edge) { - assertFatal( - edge < static_cast(layout_.position.size()), - "Edge must be top/left/bottom/right"); - layout_.position[edge] = position; +void Node::setLayoutPosition(float position, Edge edge) { + layout_.setPosition(edge, position); } void Node::setLayoutComputedFlexBasisGeneration( @@ -498,8 +483,8 @@ void Node::setLayoutHadOverflow(bool hadOverflow) { layout_.setHadOverflow(hadOverflow); } -void Node::setLayoutDimension(float dimensionValue, Dimension dimension) { - layout_.setDimension(dimension, dimensionValue); +void Node::setLayoutDimension(float LengthValue, Dimension dimension) { + layout_.setDimension(dimension, LengthValue); } // If both left and right are defined, then use left. Otherwise return +left or @@ -537,13 +522,13 @@ void Node::setPosition( const float relativePositionCross = relativePosition(crossAxis, directionRespectingRoot, crossSize); - const YGEdge mainAxisLeadingEdge = + const Edge mainAxisLeadingEdge = getInlineStartEdgeUsingErrata(mainAxis, direction); - const YGEdge mainAxisTrailingEdge = + const Edge mainAxisTrailingEdge = getInlineEndEdgeUsingErrata(mainAxis, direction); - const YGEdge crossAxisLeadingEdge = + const Edge crossAxisLeadingEdge = getInlineStartEdgeUsingErrata(crossAxis, direction); - const YGEdge crossAxisTrailingEdge = + const Edge crossAxisTrailingEdge = getInlineEndEdgeUsingErrata(crossAxis, direction); setLayoutPosition( @@ -565,18 +550,18 @@ void Node::setPosition( } YGValue Node::getFlexStartMarginValue(FlexDirection axis) const { - if (isRow(axis) && style_.margin()[YGEdgeStart].isDefined()) { - return style_.margin()[YGEdgeStart]; + if (isRow(axis) && style_.margin(Edge::Start).isDefined()) { + return style_.margin(Edge::Start); } else { - return style_.margin()[flexStartEdge(axis)]; + return style_.margin(flexStartEdge(axis)); } } YGValue Node::marginTrailingValue(FlexDirection axis) const { - if (isRow(axis) && style_.margin()[YGEdgeEnd].isDefined()) { - return style_.margin()[YGEdgeEnd]; + if (isRow(axis) && style_.margin(Edge::End).isDefined()) { + return style_.margin(Edge::End); } else { - return style_.margin()[flexEndEdge(axis)]; + return style_.margin(flexEndEdge(axis)); } } diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/Node.h b/packages/react-native/ReactCommon/yoga/yoga/node/Node.h index 601e153fea8a99..0cb9fabc8ea8af 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/Node.h +++ b/packages/react-native/ReactCommon/yoga/yoga/node/Node.h @@ -16,11 +16,11 @@ #include #include #include +#include #include #include #include #include -#include #include // Tag struct used to form the opaque YGNodeRef for the public C API @@ -53,18 +53,24 @@ class YG_EXPORT Node : public ::YGNode { Direction direction, const float axisSize) const; - YGEdge getInlineStartEdgeUsingErrata( + Edge getInlineStartEdgeUsingErrata( FlexDirection flexDirection, Direction direction) const; - YGEdge getInlineEndEdgeUsingErrata( + Edge getInlineEndEdgeUsingErrata( FlexDirection flexDirection, Direction direction) const; void useWebDefaults() { - style_.flexDirection() = FlexDirection::Row; - style_.alignContent() = Align::Stretch; + style_.setFlexDirection(FlexDirection::Row); + style_.setAlignContent(Align::Stretch); } + template + Style::Length computeEdgeValueForColumn(Edge edge) const; + + template + Style::Length computeEdgeValueForRow(Edge rowEdge, Edge edge) const; + // DANGER DANGER DANGER! // If the node assigned to has children, we'd either have to deallocate // them (potentially incorrect) or ignore them (danger of leaks). Only ever @@ -189,15 +195,6 @@ class YG_EXPORT Node : public ::YGNode { return resolvedDimensions_[static_cast(dimension)]; } - static CompactValue computeEdgeValueForColumn( - const Style::Edges& edges, - YGEdge edge); - - static CompactValue computeEdgeValueForRow( - const Style::Edges& edges, - YGEdge rowEdge, - YGEdge edge); - // Methods related to positions, margin, padding and border bool isFlexStartPositionDefined(FlexDirection axis) const; bool isInlineStartPositionDefined(FlexDirection axis, Direction direction) @@ -330,12 +327,12 @@ class YG_EXPORT Node : public ::YGNode { uint32_t computedFlexBasisGeneration); void setLayoutMeasuredDimension(float measuredDimension, Dimension dimension); void setLayoutHadOverflow(bool hadOverflow); - void setLayoutDimension(float dimensionValue, Dimension dimension); + void setLayoutDimension(float LengthValue, Dimension dimension); void setLayoutDirection(Direction direction); - void setLayoutMargin(float margin, YGEdge edge); - void setLayoutBorder(float border, YGEdge edge); - void setLayoutPadding(float padding, YGEdge edge); - void setLayoutPosition(float position, YGEdge edge); + void setLayoutMargin(float margin, Edge edge); + void setLayoutBorder(float border, Edge edge); + void setLayoutPadding(float padding, Edge edge); + void setLayoutPosition(float position, Edge edge); void setPosition( const Direction direction, const float mainSize, diff --git a/packages/react-native/ReactCommon/yoga/yoga/style/CompactValue.h b/packages/react-native/ReactCommon/yoga/yoga/style/CompactValue.h index a6ca3f1283e175..c32dd9276f1ede 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/style/CompactValue.h +++ b/packages/react-native/ReactCommon/yoga/yoga/style/CompactValue.h @@ -52,6 +52,10 @@ class YG_EXPORT CompactValue { template static CompactValue of(float value) noexcept { + if (yoga::isUndefined(value) || std::isinf(value)) { + return ofUndefined(); + } + if (value == 0.0f || (value < LOWER_BOUND && value > -LOWER_BOUND)) { constexpr auto zero = Unit == YGUnitPercent ? ZERO_BITS_PERCENT : ZERO_BITS_POINT; @@ -71,16 +75,6 @@ class YG_EXPORT CompactValue { return {data}; } - template - static CompactValue ofMaybe(float value) noexcept { - return std::isnan(value) || std::isinf(value) ? ofUndefined() - : of(value); - } - - static constexpr CompactValue ofZero() noexcept { - return CompactValue{ZERO_BITS_POINT}; - } - static constexpr CompactValue ofUndefined() noexcept { return CompactValue{}; } @@ -168,10 +162,6 @@ template <> CompactValue CompactValue::of(float) noexcept = delete; template <> CompactValue CompactValue::of(float) noexcept = delete; -template <> -CompactValue CompactValue::ofMaybe(float) noexcept = delete; -template <> -CompactValue CompactValue::ofMaybe(float) noexcept = delete; constexpr bool operator==(CompactValue a, CompactValue b) noexcept { return a.repr_ == b.repr_; diff --git a/packages/react-native/ReactCommon/yoga/yoga/style/Style.h b/packages/react-native/ReactCommon/yoga/yoga/style/Style.h index 3eb5cadd195e16..530cbb75c309ed 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/style/Style.h +++ b/packages/react-native/ReactCommon/yoga/yoga/style/Style.h @@ -14,11 +14,11 @@ #include -#include #include #include #include #include +#include #include #include #include @@ -27,291 +27,195 @@ #include #include #include +#include namespace facebook::yoga { class YG_EXPORT Style { - template - using Values = std::array()>; - public: - using Dimensions = Values; - using Edges = Values; - using Gutters = Values; + /** + * Style::Length represents a CSS Value which may be one of: + * 1. Undefined + * 2. A keyword (e.g. auto) + * 3. A CSS value: + * a. value (e.g. 10px) + * b. value of a reference + * 4. (soon) A math function which returns a value + * + * References: + * 1. https://www.w3.org/TR/css-values-4/#lengths + * 2. https://www.w3.org/TR/css-values-4/#percentage-value + * 3. https://www.w3.org/TR/css-values-4/#mixed-percentages + * 4. https://www.w3.org/TR/css-values-4/#math + */ + using Length = CompactValue; static constexpr float DefaultFlexGrow = 0.0f; static constexpr float DefaultFlexShrink = 0.0f; static constexpr float WebDefaultFlexShrink = 1.0f; - template - struct BitfieldRef { - Style& style; - uint8_t offset; - operator T() const { - return getEnumData(style.flags, offset); - } - BitfieldRef& operator=(T x) { - setEnumData(style.flags, offset, x); - return *this; - } - }; - - template - struct Ref { - Style& style; - operator T() const { - return style.*Prop; - } - Ref& operator=(T value) { - style.*Prop = value; - return *this; - } - }; - - template Style::*Prop> - struct IdxRef { - struct Ref { - Style& style; - Idx idx; - operator CompactValue() const { - return (style.*Prop)[idx]; - } - operator YGValue() const { - return (style.*Prop)[idx]; - } - Ref& operator=(CompactValue value) { - (style.*Prop)[idx] = value; - return *this; - } - }; - - Style& style; - IdxRef& operator=(const Values& values) { - style.*Prop = values; - return *this; - } - operator const Values&() const { - return style.*Prop; - } - Ref operator[](Idx idx) { - return {style, idx}; - } - CompactValue operator[](Idx idx) const { - return (style.*Prop)[idx]; - } - }; - - Style() { - alignContent() = Align::FlexStart; - alignItems() = Align::Stretch; - } - ~Style() = default; - - private: - static constexpr uint8_t directionOffset = 0; - static constexpr uint8_t flexdirectionOffset = - directionOffset + minimumBitCount(); - static constexpr uint8_t justifyContentOffset = - flexdirectionOffset + minimumBitCount(); - static constexpr uint8_t alignContentOffset = - justifyContentOffset + minimumBitCount(); - static constexpr uint8_t alignItemsOffset = - alignContentOffset + minimumBitCount(); - static constexpr uint8_t alignSelfOffset = - alignItemsOffset + minimumBitCount(); - static constexpr uint8_t positionTypeOffset = - alignSelfOffset + minimumBitCount(); - static constexpr uint8_t flexWrapOffset = - positionTypeOffset + minimumBitCount(); - static constexpr uint8_t overflowOffset = - flexWrapOffset + minimumBitCount(); - static constexpr uint8_t displayOffset = - overflowOffset + minimumBitCount(); - - uint32_t flags = 0; - - FloatOptional flex_ = {}; - FloatOptional flexGrow_ = {}; - FloatOptional flexShrink_ = {}; - CompactValue flexBasis_ = CompactValue::ofAuto(); - Edges margin_ = {}; - Edges position_ = {}; - Edges padding_ = {}; - Edges border_ = {}; - Gutters gap_ = {}; - Dimensions dimensions_{CompactValue::ofAuto(), CompactValue::ofAuto()}; - Dimensions minDimensions_ = {}; - Dimensions maxDimensions_ = {}; - // Yoga specific properties, not compatible with flexbox specification - FloatOptional aspectRatio_ = {}; - - public: - // for library users needing a type - using ValueRepr = std::remove_reference::type; - Direction direction() const { - return getEnumData(flags, directionOffset); + return direction_; } - BitfieldRef direction() { - return {*this, directionOffset}; + void setDirection(Direction value) { + direction_ = value; } FlexDirection flexDirection() const { - return getEnumData(flags, flexdirectionOffset); + return flexDirection_; } - BitfieldRef flexDirection() { - return {*this, flexdirectionOffset}; + void setFlexDirection(FlexDirection value) { + flexDirection_ = value; } Justify justifyContent() const { - return getEnumData(flags, justifyContentOffset); + return justifyContent_; } - BitfieldRef justifyContent() { - return {*this, justifyContentOffset}; + void setJustifyContent(Justify value) { + justifyContent_ = value; } Align alignContent() const { - return getEnumData(flags, alignContentOffset); + return alignContent_; } - BitfieldRef alignContent() { - return {*this, alignContentOffset}; + void setAlignContent(Align value) { + alignContent_ = value; } Align alignItems() const { - return getEnumData(flags, alignItemsOffset); + return alignItems_; } - BitfieldRef alignItems() { - return {*this, alignItemsOffset}; + void setAlignItems(Align value) { + alignItems_ = value; } Align alignSelf() const { - return getEnumData(flags, alignSelfOffset); + return alignSelf_; } - BitfieldRef alignSelf() { - return {*this, alignSelfOffset}; + void setAlignSelf(Align value) { + alignSelf_ = value; } PositionType positionType() const { - return getEnumData(flags, positionTypeOffset); + return positionType_; } - BitfieldRef positionType() { - return {*this, positionTypeOffset}; + void setPositionType(PositionType value) { + positionType_ = value; } Wrap flexWrap() const { - return getEnumData(flags, flexWrapOffset); + return flexWrap_; } - BitfieldRef flexWrap() { - return {*this, flexWrapOffset}; + void setFlexWrap(Wrap value) { + flexWrap_ = value; } Overflow overflow() const { - return getEnumData(flags, overflowOffset); + return overflow_; } - BitfieldRef overflow() { - return {*this, overflowOffset}; + void setOverflow(Overflow value) { + overflow_ = value; } Display display() const { - return getEnumData(flags, displayOffset); + return display_; } - BitfieldRef display() { - return {*this, displayOffset}; + void setDisplay(Display value) { + display_ = value; } FloatOptional flex() const { return flex_; } - Ref flex() { - return {*this}; + void setFlex(FloatOptional value) { + flex_ = value; } FloatOptional flexGrow() const { return flexGrow_; } - Ref flexGrow() { - return {*this}; + void setFlexGrow(FloatOptional value) { + flexGrow_ = value; } FloatOptional flexShrink() const { return flexShrink_; } - Ref flexShrink() { - return {*this}; + void setFlexShrink(FloatOptional value) { + flexShrink_ = value; } - CompactValue flexBasis() const { + Style::Length flexBasis() const { return flexBasis_; } - Ref flexBasis() { - return {*this}; + void setFlexBasis(Style::Length value) { + flexBasis_ = value; } - const Edges& margin() const { - return margin_; + Style::Length margin(Edge edge) const { + return margin_[yoga::to_underlying(edge)]; } - IdxRef margin() { - return {*this}; + void setMargin(Edge edge, Style::Length value) { + margin_[yoga::to_underlying(edge)] = value; } - const Edges& position() const { - return position_; + Style::Length position(Edge edge) const { + return position_[yoga::to_underlying(edge)]; } - IdxRef position() { - return {*this}; + void setPosition(Edge edge, Style::Length value) { + position_[yoga::to_underlying(edge)] = value; } - const Edges& padding() const { - return padding_; + Style::Length padding(Edge edge) const { + return padding_[yoga::to_underlying(edge)]; } - IdxRef padding() { - return {*this}; + void setPadding(Edge edge, Style::Length value) { + padding_[yoga::to_underlying(edge)] = value; } - const Edges& border() const { - return border_; + Style::Length border(Edge edge) const { + return border_[yoga::to_underlying(edge)]; } - IdxRef border() { - return {*this}; + void setBorder(Edge edge, Style::Length value) { + border_[yoga::to_underlying(edge)] = value; } - CompactValue gap(Gutter gutter) const { + Style::Length gap(Gutter gutter) const { return gap_[yoga::to_underlying(gutter)]; } - void setGap(Gutter gutter, CompactValue value) { + void setGap(Gutter gutter, Style::Length value) { gap_[yoga::to_underlying(gutter)] = value; } - CompactValue dimension(Dimension axis) const { + Style::Length dimension(Dimension axis) const { return dimensions_[yoga::to_underlying(axis)]; } - void setDimension(Dimension axis, CompactValue value) { + void setDimension(Dimension axis, Style::Length value) { dimensions_[yoga::to_underlying(axis)] = value; } - CompactValue minDimension(Dimension axis) const { + Style::Length minDimension(Dimension axis) const { return minDimensions_[yoga::to_underlying(axis)]; } - void setMinDimension(Dimension axis, CompactValue value) { + void setMinDimension(Dimension axis, Style::Length value) { minDimensions_[yoga::to_underlying(axis)] = value; } - CompactValue maxDimension(Dimension axis) const { + Style::Length maxDimension(Dimension axis) const { return maxDimensions_[yoga::to_underlying(axis)]; } - void setMaxDimension(Dimension axis, CompactValue value) { + void setMaxDimension(Dimension axis, Style::Length value) { maxDimensions_[yoga::to_underlying(axis)] = value; } - // Yoga specific properties, not compatible with flexbox specification FloatOptional aspectRatio() const { return aspectRatio_; } - Ref aspectRatio() { - return {*this}; + void setAspectRatio(FloatOptional value) { + aspectRatio_ = value; } - CompactValue resolveColumnGap() const { + Length resolveColumnGap() const { if (gap_[yoga::to_underlying(Gutter::Column)].isDefined()) { return gap_[yoga::to_underlying(Gutter::Column)]; } else { @@ -319,7 +223,7 @@ class YG_EXPORT Style { } } - CompactValue resolveRowGap() const { + Style::Length resolveRowGap() const { if (gap_[yoga::to_underlying(Gutter::Row)].isDefined()) { return gap_[yoga::to_underlying(Gutter::Row)]; } else { @@ -328,7 +232,14 @@ class YG_EXPORT Style { } bool operator==(const Style& other) const { - return flags == other.flags && inexactEquals(flex_, other.flex_) && + return direction_ == other.direction_ && + flexDirection_ == other.flexDirection_ && + justifyContent_ == other.justifyContent_ && + alignContent_ == other.alignContent_ && + alignItems_ == other.alignItems_ && alignSelf_ == other.alignSelf_ && + positionType_ == other.positionType_ && flexWrap_ == other.flexWrap_ && + overflow_ == other.overflow_ && display_ == other.display_ && + inexactEquals(flex_, other.flex_) && inexactEquals(flexGrow_, other.flexGrow_) && inexactEquals(flexShrink_, other.flexShrink_) && inexactEquals(flexBasis_, other.flexBasis_) && @@ -346,6 +257,38 @@ class YG_EXPORT Style { bool operator!=(const Style& other) const { return !(*this == other); } + + private: + using Dimensions = std::array()>; + using Edges = std::array()>; + using Gutters = std::array()>; + + Direction direction_ : bitCount() = Direction::Inherit; + FlexDirection flexDirection_ + : bitCount() = FlexDirection::Column; + Justify justifyContent_ : bitCount() = Justify::FlexStart; + Align alignContent_ : bitCount() = Align::FlexStart; + Align alignItems_ : bitCount() = Align::Stretch; + Align alignSelf_ : bitCount() = Align::Auto; + PositionType positionType_ + : bitCount() = PositionType::Relative; + Wrap flexWrap_ : bitCount() = Wrap::NoWrap; + Overflow overflow_ : bitCount() = Overflow::Visible; + Display display_ : bitCount() = Display::Flex; + + FloatOptional flex_{}; + FloatOptional flexGrow_{}; + FloatOptional flexShrink_{}; + Style::Length flexBasis_{value::ofAuto()}; + Edges margin_{}; + Edges position_{}; + Edges padding_{}; + Edges border_{}; + Gutters gap_{}; + Dimensions dimensions_{value::ofAuto(), value::ofAuto()}; + Dimensions minDimensions_{}; + Dimensions maxDimensions_{}; + FloatOptional aspectRatio_{}; }; } // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/style/ValueFactories.h b/packages/react-native/ReactCommon/yoga/yoga/style/ValueFactories.h new file mode 100644 index 00000000000000..65486347b0a52c --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/yoga/style/ValueFactories.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook::yoga::value { + +/** + * Canonical unit (one YGUnitPoint) + */ +inline CompactValue points(float value) { + return CompactValue::of(value); +} + +/** + * Percent of reference + */ +inline CompactValue percent(float value) { + return CompactValue::of(value); +} + +/** + * "auto" keyword + */ +inline CompactValue ofAuto() { + return CompactValue::ofAuto(); +} + +/** + * Undefined + */ +inline CompactValue undefined() { + return CompactValue::ofUndefined(); +} + +} // namespace facebook::yoga::value diff --git a/packages/react-native/cli.js b/packages/react-native/cli.js index 4d84dd6b470d5a..4547d287ec955e 100755 --- a/packages/react-native/cli.js +++ b/packages/react-native/cli.js @@ -40,7 +40,7 @@ async function getLatestVersion(registryHost = DEFAULT_REGISTRY_HOST) { } /** - * npx react-native -> @react-native-comminity/cli + * npx react-native -> @react-native-community/cli * * Will perform a version check and warning if you're not running the latest community cli when executed using npx. If * you know what you're doing, you can skip this check: diff --git a/packages/react-native/gradle/libs.versions.toml b/packages/react-native/gradle/libs.versions.toml index 48ea84cc9acabd..b95a8de23c2755 100644 --- a/packages/react-native/gradle/libs.versions.toml +++ b/packages/react-native/gradle/libs.versions.toml @@ -5,7 +5,7 @@ targetSdk = "34" compileSdk = "34" buildTools = "34.0.0" # Dependencies versions -agp = "8.1.2" +agp = "8.2.0" androidx-annotation = "1.6.0" androidx-appcompat = "1.6.1" androidx-autofill = "1.1.0" @@ -21,7 +21,7 @@ javax-annotation-api = "1.3.2" javax-inject = "1" jsr305 = "3.0.2" junit = "4.13.2" -kotlin = "1.8.0" +kotlin = "1.8.22" mockito = "3.12.4" nexus-publish = "1.3.0" okhttp = "4.9.2" diff --git a/packages/react-native/index.js b/packages/react-native/index.js index 0e4376a60f76db..3e0a2396cff6cd 100644 --- a/packages/react-native/index.js +++ b/packages/react-native/index.js @@ -285,7 +285,7 @@ module.exports = { 'pushNotificationIOS-moved', 'PushNotificationIOS has been extracted from react-native core and will be removed in a future release. ' + "It can now be installed and imported from '@react-native-community/push-notification-ios' instead of 'react-native'. " + - 'See https://github.com/react-native-push-notification-ios/push-notification-ios', + 'See https://github.com/react-native-push-notification/ios', ); return require('./Libraries/PushNotificationIOS/PushNotificationIOS'); }, @@ -429,7 +429,8 @@ if (__DEV__) { invariant( false, 'ART has been removed from React Native. ' + - "It can now be installed and imported from '@react-native-community/art' instead of 'react-native'. " + + "Please upgrade to use either 'react-native-svg' or a similar package. " + + "If you cannot upgrade to a different library, please install the deprecated '@react-native-community/art' package. " + 'See https://github.com/react-native-art/art', ); }, @@ -509,7 +510,7 @@ if (__DEV__) { invariant( false, 'CameraRoll has been removed from React Native. ' + - "It can now be installed and imported from '@react-native-community/cameraroll' instead of 'react-native'. " + + "It can now be installed and imported from '@react-native-camera-roll/camera-roll' instead of 'react-native'. " + 'See https://github.com/react-native-cameraroll/react-native-cameraroll', ); }, @@ -622,7 +623,7 @@ if (__DEV__) { invariant( false, 'SegmentedControlIOS has been removed from React Native. ' + - "It can now be installed and imported from '@react-native-community/segmented-checkbox' instead of 'react-native'." + + "It can now be installed and imported from '@react-native-segmented-control/segmented-control' instead of 'react-native'." + 'See https://github.com/react-native-segmented-control/segmented-control', ); }, @@ -700,7 +701,7 @@ if (__DEV__) { invariant( false, 'MaskedViewIOS has been removed from React Native. ' + - "It can now be installed and imported from '@react-native-community/react-native-masked-view' instead of 'react-native'. " + + "It can now be installed and imported from '@react-native-masked-view/masked-view' instead of 'react-native'. " + 'See https://github.com/react-native-masked-view/masked-view', ); }, @@ -730,7 +731,7 @@ if (__DEV__) { invariant( false, 'ImagePickerIOS has been removed from React Native. ' + - "Please upgrade to use either '@react-native-community/react-native-image-picker' or 'expo-image-picker'. " + + "Please upgrade to use either 'react-native-image-picker' or 'expo-image-picker'. " + "If you cannot upgrade to a different library, please install the deprecated '@react-native-community/image-picker-ios' package. " + 'See https://github.com/rnc-archive/react-native-image-picker-ios', ); diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 37f839703342b1..f80ea276738e13 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -48,6 +48,7 @@ "React.podspec", "React", "ReactAndroid", + "ReactApple", "ReactCommon", "README.md", "rn-get-polyfills.js", diff --git a/packages/react-native/scripts/cocoapods/__tests__/codegen-test.rb b/packages/react-native/scripts/cocoapods/__tests__/codegen-test.rb index 6987399ad87f6d..3fcce19e09d728 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/codegen-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/codegen-test.rb @@ -40,191 +40,6 @@ def teardown DirMock.reset() end - # ============================================== # - # Test - setup_fabric # - # ============================================== # - def testCheckAndGenerateEmptyThirdPartyProvider_whenFileAlreadyExists_doNothing() - - # Arrange - FileMock.mocked_existing_files([ - @base_path + "/" + @prefix + "/React/Fabric/" + @third_party_provider_header, - @base_path + "/" + @prefix + "/React/Fabric/" + @third_party_provider_implementation, - ]) - - # Act - checkAndGenerateEmptyThirdPartyProvider!(@prefix, false, dir_manager: DirMock, file_manager: FileMock) - - # Assert - assert_equal(Pathname.pwd_invocation_count, 1) - assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1) - assert_equal(FileMock.exist_invocation_params, [ - @base_path + "/" + @prefix + "/React/Fabric/" + @third_party_provider_header, - @base_path + "/" + @prefix + "/React/Fabric/" + @third_party_provider_implementation, - ]) - assert_equal(DirMock.exist_invocation_params, []) - assert_equal(Pod::UI.collected_messages, []) - assert_equal($collected_commands, []) - assert_equal(FileMock.open_files.length, 0) - assert_equal(Pod::Executable.executed_commands.length, 0) - end - - def testCheckAndGenerateEmptyThirdPartyProvider_whenHeaderMissingAndCodegenMissing_dontBuildCodegen() - - # Arrange - FileMock.mocked_existing_files([ - @base_path + "/build/" + @third_party_provider_implementation, - ]) - - # Act - assert_nothing_raised { - checkAndGenerateEmptyThirdPartyProvider!(@prefix, false, dir_manager: DirMock, file_manager: FileMock) - } - - # Assert - assert_equal(Pathname.pwd_invocation_count, 1) - assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1) - assert_equal(FileMock.exist_invocation_params, [ - @base_path + "/" + @prefix + "/React/Fabric/" + @third_party_provider_header, - @base_path + "/" + @prefix + "/React/Fabric/tmpSchemaList.txt", - ]) - assert_equal(DirMock.exist_invocation_params, [ - @base_path + "/"+ @prefix + "/../react-native-codegen", - ]) - assert_equal(Pod::UI.collected_messages, [ - "[Codegen] generating an empty RCTThirdPartyFabricComponentsProvider", - ]) - assert_equal($collected_commands, []) - assert_equal(FileMock.open_files.length, 1) - assert_equal(Pod::Executable.executed_commands.length, 1) - end - - def testCheckAndGenerateEmptyThirdPartyProvider_whenImplementationMissingAndCodegenrepoExists_dontBuildCodegen() - - # Arrange - FileMock.mocked_existing_files([ - @base_path + "/" + @prefix + "/React/Fabric/" + @third_party_provider_header, - @base_path + "/" + @prefix + "/React/Fabric/tmpSchemaList.txt" - ]) - - DirMock.mocked_existing_dirs([ - @base_path + "/"+ @prefix + "/../react-native-codegen", - @base_path + "/"+ @prefix + "/../react-native-codegen/lib" - ]) - - # Act - checkAndGenerateEmptyThirdPartyProvider!(@prefix, false, dir_manager: DirMock, file_manager: FileMock) - - # Assert - assert_equal(Pathname.pwd_invocation_count, 1) - assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1) - assert_equal(FileMock.exist_invocation_params, [ - @base_path + "/" + @prefix + "/React/Fabric/" + @third_party_provider_header, - @base_path + "/" + @prefix + "/React/Fabric/" + @third_party_provider_implementation, - @base_path + "/" + @prefix + "/React/Fabric/tmpSchemaList.txt", - ]) - assert_equal(DirMock.exist_invocation_params, [ - @base_path + "/"+ @prefix + "/../react-native-codegen", - @base_path + "/"+ @prefix + "/../react-native-codegen/lib", - ]) - assert_equal(Pod::UI.collected_messages, ["[Codegen] generating an empty RCTThirdPartyFabricComponentsProvider"]) - assert_equal($collected_commands, []) - assert_equal(FileMock.open_invocation_count, 1) - assert_equal(FileMock.open_files_with_mode[@prefix + "/React/Fabric/tmpSchemaList.txt"], nil) - assert_equal(FileMock.open_files[0].collected_write, ["[]"]) - assert_equal(FileMock.open_files[0].fsync_invocation_count, 1) - assert_equal(Pod::Executable.executed_commands[0], { - "command" => "node", - "arguments" => [ - @base_path + "/" + @prefix + "/scripts/generate-provider-cli.js", - "--platform", 'ios', - "--schemaListPath", @base_path + "/" + @prefix + "/React/Fabric/tmpSchemaList.txt", - "--outputDir", @base_path + "/" + @prefix + "/React/Fabric" - ] - }) - assert_equal(FileMock.delete_invocation_count, 1) - assert_equal(FileMock.deleted_files, [ @base_path + "/" + @prefix + "/React/Fabric/tmpSchemaList.txt"]) - end - - def testCheckAndGenerateEmptyThirdPartyProvider_whenBothMissing_buildCodegen() - # Arrange - codegen_cli_path = @base_path + "/" + @prefix + "/../react-native-codegen" - DirMock.mocked_existing_dirs([ - codegen_cli_path, - ]) - # Act - checkAndGenerateEmptyThirdPartyProvider!(@prefix, false, dir_manager: DirMock, file_manager: FileMock) - - # Assert - assert_equal(Pathname.pwd_invocation_count, 1) - assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1) - assert_equal(FileMock.exist_invocation_params, [ - @base_path + "/" + @prefix + "/React/Fabric/" + @third_party_provider_header, - @base_path + "/" + @prefix + "/React/Fabric/" + @tmp_schema_list_file - ]) - assert_equal(DirMock.exist_invocation_params, [ - codegen_cli_path, - codegen_cli_path + "/lib", - ]) - assert_equal(Pod::UI.collected_messages, [ - "[Codegen] building #{codegen_cli_path}", - "[Codegen] generating an empty RCTThirdPartyFabricComponentsProvider" - ]) - assert_equal($collected_commands, ["~/app/ios/../../../react-native-codegen/scripts/oss/build.sh"]) - assert_equal(FileMock.open_files[0].collected_write, ["[]"]) - assert_equal(FileMock.open_files[0].fsync_invocation_count, 1) - assert_equal(Pod::Executable.executed_commands[0], { - "command" => "node", - "arguments" => [ - @base_path + "/" + @prefix + "/scripts/generate-provider-cli.js", - "--platform", 'ios', - "--schemaListPath", @base_path + "/" + @prefix + "/React/Fabric/" + @tmp_schema_list_file, - "--outputDir", @base_path + "/" + @prefix + "/React/Fabric" - ] - }) - end - - def testCheckAndGenerateEmptyThirdPartyProvider_withAbsoluteReactNativePath_buildCodegen() - # Arrange - rn_path = 'packages/react-native' - codegen_cli_path = rn_path + "/../react-native-codegen" - DirMock.mocked_existing_dirs([ - @base_path + "/" + codegen_cli_path, - ]) - - # Act - checkAndGenerateEmptyThirdPartyProvider!(rn_path, false, dir_manager: DirMock, file_manager: FileMock) - - # Assert - assert_equal(Pathname.pwd_invocation_count, 1) - assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1) - assert_equal(FileMock.exist_invocation_params, [ - @base_path + "/" + rn_path + "/React/Fabric/" + @third_party_provider_header, - @base_path + "/" + rn_path + "/React/Fabric/" + @tmp_schema_list_file - ]) - assert_equal(DirMock.exist_invocation_params, [ - @base_path + "/" + codegen_cli_path, - @base_path + "/" + codegen_cli_path + "/lib", - ]) - assert_equal(Pod::UI.collected_messages, [ - "[Codegen] building #{@base_path + "/" + codegen_cli_path}", - "[Codegen] generating an empty RCTThirdPartyFabricComponentsProvider" - ]) - assert_equal($collected_commands, [ - @base_path + "/" + rn_path + "/../react-native-codegen/scripts/oss/build.sh", - ]) - assert_equal(FileMock.open_files[0].collected_write, ["[]"]) - assert_equal(FileMock.open_files[0].fsync_invocation_count, 1) - assert_equal(Pod::Executable.executed_commands[0], { - "command" => "node", - "arguments" => [ - @base_path + "/" + rn_path + "/scripts/generate-provider-cli.js", - "--platform", 'ios', - "--schemaListPath", @base_path + "/" + rn_path + "/React/Fabric/" + @tmp_schema_list_file, - "--outputDir", @base_path + "/" + rn_path + "/React/Fabric" - ] - }) - end - # ================= # # Test - RunCodegen # # ================= # @@ -250,36 +65,4 @@ def testRunCodegen_whenNewArchEnabled_runsCodegen assert_equal(codegen_utils_mock.get_react_codegen_spec_params, []) assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, []) end - - def testRunCodegen_whenNewArchDisabled_runsCodegen - # Arrange - app_path = "~/app" - config_file = "" - package_json_file = "~/app/package.json" - codegen_specs = { "name" => "React-Codegen" } - codegen_utils_mock = CodegenUtilsMock.new(:react_codegen_spec => codegen_specs) - - # Act - run_codegen!( - app_path, - config_file, - :new_arch_enabled => false, - :fabric_enabled => true, - :package_json_file => package_json_file, - :codegen_utils => codegen_utils_mock) - - # Assert - assert_equal(codegen_utils_mock.use_react_native_codegen_discovery_params, []) - assert_equal(codegen_utils_mock.get_react_codegen_spec_params, [{ - :fabric_enabled => true, - :folly_version=>"2023.08.07.00", - :package_json_file => "~/app/package.json", - :script_phases => nil - }]) - assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, [{ - :codegen_output_dir=>"build/generated/ios", - :react_codegen_spec=>{"name"=>"React-Codegen"} - }]) - - end end diff --git a/packages/react-native/scripts/cocoapods/__tests__/codegen_utils-test.rb b/packages/react-native/scripts/cocoapods/__tests__/codegen_utils-test.rb index 6dd22eb30142b7..57dbafd8f04405 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/codegen_utils-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/codegen_utils-test.rb @@ -93,25 +93,6 @@ def testGenerateReactCodegenPodspec_whenItHasNotBeenAlreadyGenerated_generatesIt # ========================== # # Test - GetReactCodegenSpec # # ========================== # - - def testGetReactCodegenSpec_whenFabricDisabledAndNoScriptPhases_generatesAPodspec - # Arrange - FileMock.files_to_read('package.json' => '{ "version": "99.98.97"}') - - # Act - podspec = CodegenUtils.new().get_react_codegen_spec( - 'package.json', - :fabric_enabled => false, - :hermes_enabled => true, - :script_phases => nil, - :file_manager => FileMock - ) - - # Assert - assert_equal(podspec, get_podspec_no_fabric_no_script()) - assert_equal(Pod::UI.collected_messages, []) - end - def testGetReactCodegenSpec_whenFabricEnabledAndScriptPhases_generatesAPodspec # Arrange FileMock.files_to_read('package.json' => '{ "version": "99.98.97"}') @@ -119,7 +100,6 @@ def testGetReactCodegenSpec_whenFabricEnabledAndScriptPhases_generatesAPodspec # Act podspec = CodegenUtils.new().get_react_codegen_spec( 'package.json', - :fabric_enabled => true, :hermes_enabled => true, :script_phases => "echo Test Script Phase", :file_manager => FileMock @@ -138,7 +118,7 @@ def testGetReactCodegenSpec_whenUseFrameworksAndNewArch_generatesAPodspec # Act podspec = CodegenUtils.new().get_react_codegen_spec( 'package.json', - :fabric_enabled => true, + :hermes_enabled => true, :script_phases => nil, :file_manager => FileMock @@ -380,11 +360,9 @@ def testUseReactCodegenDiscovery_whenParametersAreGood_executeCodegen :app_path => app_path, :config_file_dir => "", :config_key => "codegenConfig", - :fabric_enabled => false, :react_native_path => "../node_modules/react-native"} ]) assert_equal(codegen_utils_mock.get_react_codegen_spec_params, [{ - :fabric_enabled => false, :folly_version=>"2023.08.07.00", :package_json_file => "#{app_path}/ios/../node_modules/react-native/package.json", :script_phases => "echo TestScript" @@ -399,7 +377,6 @@ def testUseReactCodegenDiscovery_whenParametersAreGood_executeCodegen "arguments"=> ["~/app/ios/../node_modules/react-native/scripts/generate-codegen-artifacts.js", "-p", "~/app", "-o", Pod::Config.instance.installation_root, - "-e", "false", "-c", ""] } ]) @@ -561,14 +538,12 @@ def get_podspec_no_fabric_no_script }, 'dependencies': { "DoubleConversion": [], - "FBReactNativeSpec": [], "RCT-Folly": [], "RCTRequired": [], "RCTTypeSafety": [], "React-Core": [], "React-jsi": [], "React-jsiexecutor": [], - "React-rncore": [], "ReactCommon/turbomodule/bridging": [], "ReactCommon/turbomodule/core": [], "hermes-engine": [], @@ -583,8 +558,8 @@ def get_podspec_fabric_and_script_phases(script_phases) specs[:dependencies].merge!({ 'React-graphics': [], - 'React-rncore': [], 'React-Fabric': [], + 'React-FabricImage': [], 'React-utils': [], 'React-debug': [], 'React-rendererdebug': [], @@ -604,6 +579,7 @@ def get_podspec_when_use_frameworks specs[:dependencies].merge!({ 'React-graphics': [], 'React-Fabric': [], + 'React-FabricImage': [], 'React-utils': [], 'React-debug': [], 'React-rendererdebug': [], diff --git a/packages/react-native/scripts/cocoapods/__tests__/new_architecture-test.rb b/packages/react-native/scripts/cocoapods/__tests__/new_architecture-test.rb index 9dcd4a3f15b0d2..0b5f77d9ee4667 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/new_architecture-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/new_architecture-test.rb @@ -120,12 +120,12 @@ def test_modifyFlagsForNewArch_whenOnNewArchAndIsRelease_updateFlags assert_equal(second_xcconfig.save_as_invocation, ["a/path/Second.xcconfig"]) assert_equal(react_core_debug_config.build_settings["OTHER_CPLUSPLUSFLAGS"], "$(inherited) -DRCT_NEW_ARCH_ENABLED=1 -DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_CFG_NO_COROUTINES=1 -DFOLLY_HAVE_CLOCK_GETTIME=1") assert_nil(react_core_debug_config.build_settings["OTHER_CFLAGS"]) - assert_equal(react_core_release_config.build_settings["OTHER_CPLUSPLUSFLAGS"], "$(inherited) -DRCT_NEW_ARCH_ENABLED=1 -DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_CFG_NO_COROUTINES=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -DNDEBUG") - assert_equal(react_core_release_config.build_settings["OTHER_CFLAGS"], "$(inherited) -DNDEBUG") + assert_equal(react_core_release_config.build_settings["OTHER_CPLUSPLUSFLAGS"], "$(inherited) -DRCT_NEW_ARCH_ENABLED=1 -DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_CFG_NO_COROUTINES=1 -DFOLLY_HAVE_CLOCK_GETTIME=1") + assert_nil(react_core_release_config.build_settings["OTHER_CFLAGS"]) assert_equal(yoga_debug_config.build_settings["OTHER_CPLUSPLUSFLAGS"], "$(inherited)") assert_nil(yoga_debug_config.build_settings["OTHER_CFLAGS"]) - assert_equal(yoga_release_config.build_settings["OTHER_CPLUSPLUSFLAGS"], "$(inherited) -DNDEBUG") - assert_equal(yoga_release_config.build_settings["OTHER_CFLAGS"], "$(inherited) -DNDEBUG") + assert_equal(yoga_release_config.build_settings["OTHER_CPLUSPLUSFLAGS"], "$(inherited)") + assert_nil(yoga_release_config.build_settings["OTHER_CFLAGS"]) end # =================================== # @@ -188,7 +188,22 @@ def test_installModulesDependencies_whenNewArchDisabledAndSearchPathsAndCompiler [ { :dependency_name => "React-Core" }, { :dependency_name => "RCT-Folly", "version"=>"2023.08.07.00" }, - { :dependency_name => "glog" } + { :dependency_name => "glog" }, + { :dependency_name => "React-RCTFabric" }, + { :dependency_name => "React-Codegen" }, + { :dependency_name => "RCTRequired" }, + { :dependency_name => "RCTTypeSafety" }, + { :dependency_name => "ReactCommon/turbomodule/bridging" }, + { :dependency_name => "ReactCommon/turbomodule/core" }, + { :dependency_name => "React-NativeModulesApple" }, + { :dependency_name => "Yoga" }, + { :dependency_name => "React-Fabric" }, + { :dependency_name => "React-graphics" }, + { :dependency_name => "React-utils" }, + { :dependency_name => "React-debug" }, + { :dependency_name => "React-ImageManager" }, + { :dependency_name => "React-rendererdebug" }, + { :dependency_name => "hermes-engine" } ] ) end diff --git a/packages/react-native/scripts/cocoapods/__tests__/test_utils/CodegenUtilsMock.rb b/packages/react-native/scripts/cocoapods/__tests__/test_utils/CodegenUtilsMock.rb index e6b4174a17e043..4c0cc8d6cbeaa3 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/test_utils/CodegenUtilsMock.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/test_utils/CodegenUtilsMock.rb @@ -58,7 +58,6 @@ def get_react_codegen_script_phases( ) @get_react_codegen_script_phases_params.push({ app_path: app_path, - fabric_enabled: fabric_enabled, config_file_dir: config_file_dir, react_native_path: react_native_path, config_key: config_key @@ -66,11 +65,10 @@ def get_react_codegen_script_phases( return @react_codegen_script_phases end - def get_react_codegen_spec(package_json_file, folly_version: '2023.08.07.00', fabric_enabled: false, hermes_enabled: true, script_phases: nil) + def get_react_codegen_spec(package_json_file, folly_version: '2023.08.07.00', hermes_enabled: true, script_phases: nil) @get_react_codegen_spec_params.push({ package_json_file: package_json_file, folly_version: folly_version, - fabric_enabled: fabric_enabled, script_phases: script_phases }) return @react_codegen_spec diff --git a/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb b/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb index 2acd46732eac7d..cc6963c73a4fc0 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb @@ -16,6 +16,7 @@ require_relative "./test_utils/XcodeprojMock.rb" require_relative "./test_utils/XcodebuildMock.rb" require_relative "./test_utils/SpecMock.rb" +require_relative "./test_utils/InstallerMock.rb" class UtilsTests < Test::Unit::TestCase def setup @@ -790,68 +791,6 @@ def test_updateSearchPaths_whenNotUseFrameworks_addsSearchPaths end end - # ============================= # - # Test - Apply Flags For Fabric # - # ============================= # - def test_applyFlagsForFabric_whenFabricEnabled_addsTheFlag - # Arrange - first_target = prepare_target("FirstTarget") - second_target = prepare_target("SecondTarget") - third_target = prepare_target("ThirdTarget", "com.apple.product-type.bundle") - user_project_mock = UserProjectMock.new("a/path", [ - prepare_config("Debug"), - prepare_config("Release"), - ], - :native_targets => [ - first_target, - second_target - ] - ) - pods_projects_mock = PodsProjectMock.new([third_target], {"hermes-engine" => {}}) - installer = InstallerMock.new(pods_projects_mock, [ - AggregatedProjectMock.new(user_project_mock) - ]) - - # Act - ReactNativePodsUtils.apply_flags_for_fabric(installer, fabric_enabled: true) - - # Assert - user_project_mock.build_configurations.each do |config| - received_cflags = config.build_settings["OTHER_CFLAGS"] - expected_cflags = "$(inherited) -DRN_FABRIC_ENABLED" - assert_equal(received_cflags, expected_cflags) - end - - end - - def test_applyFlagsForFabric_whenFabricDisabled_doNothing - # Arrange - first_target = prepare_target("FirstTarget") - second_target = prepare_target("SecondTarget") - third_target = prepare_target("ThirdTarget", "com.apple.product-type.bundle") - user_project_mock = UserProjectMock.new("/a/path", [ - prepare_config("Debug"), - prepare_config("Release"), - ], - :native_targets => [ - first_target, - second_target - ] - ) - pods_projects_mock = PodsProjectMock.new([third_target], {"hermes-engine" => {}}) - installer = InstallerMock.new(pods_projects_mock, [ - AggregatedProjectMock.new(user_project_mock) - ]) - - # Act - ReactNativePodsUtils.apply_flags_for_fabric(installer, fabric_enabled: false) - - # Assert - user_project_mock.build_configurations.each do |config| - assert_equal(config.build_settings["OTHER_CFLAGS"], "$(inherited)") - end - end - # ============================== # # Test - Apply ATS configuration # # ============================== # @@ -1070,6 +1009,78 @@ def test_addDependencies_whenSubspecsAndHeaderSearchPathAndVersionWithAdditional assert_equal(spec.to_hash["pod_target_xcconfig"], { "HEADER_SEARCH_PATHS" => expected_search_paths}) end + + def test_add_flag_to_map_with_inheritance_whenUsedWithBuildConfigBuildSettings + # Arrange + empty_config = BuildConfigurationMock.new("EmptyConfig") + initialized_config = BuildConfigurationMock.new("InitializedConfig", { + "OTHER_CPLUSPLUSFLAGS" => "INIT_FLAG" + }) + twiceProcessed_config = BuildConfigurationMock.new("TwiceProcessedConfig"); + test_flag = " -DTEST_FLAG=1" + + # Act + ReactNativePodsUtils.add_flag_to_map_with_inheritance(empty_config.build_settings, "OTHER_CPLUSPLUSFLAGS", test_flag) + ReactNativePodsUtils.add_flag_to_map_with_inheritance(initialized_config.build_settings, "OTHER_CPLUSPLUSFLAGS", test_flag) + ReactNativePodsUtils.add_flag_to_map_with_inheritance(twiceProcessed_config.build_settings, "OTHER_CPLUSPLUSFLAGS", test_flag) + ReactNativePodsUtils.add_flag_to_map_with_inheritance(twiceProcessed_config.build_settings, "OTHER_CPLUSPLUSFLAGS", test_flag) + + # Assert + assert_equal("$(inherited)" + test_flag, empty_config.build_settings["OTHER_CPLUSPLUSFLAGS"]) + assert_equal("$(inherited) INIT_FLAG" + test_flag, initialized_config.build_settings["OTHER_CPLUSPLUSFLAGS"]) + assert_equal("$(inherited)" + test_flag, twiceProcessed_config.build_settings["OTHER_CPLUSPLUSFLAGS"]) + end + + def test_add_flag_to_map_with_inheritance_whenUsedWithXCConfigAttributes + # Arrange + empty_xcconfig = XCConfigMock.new("EmptyConfig") + initialized_xcconfig = XCConfigMock.new("InitializedConfig", attributes: { + "OTHER_CPLUSPLUSFLAGS" => "INIT_FLAG" + }) + twiceProcessed_xcconfig = XCConfigMock.new("TwiceProcessedConfig"); + test_flag = " -DTEST_FLAG=1" + + # Act + ReactNativePodsUtils.add_flag_to_map_with_inheritance(empty_xcconfig.attributes, "OTHER_CPLUSPLUSFLAGS", test_flag) + ReactNativePodsUtils.add_flag_to_map_with_inheritance(initialized_xcconfig.attributes, "OTHER_CPLUSPLUSFLAGS", test_flag) + ReactNativePodsUtils.add_flag_to_map_with_inheritance(twiceProcessed_xcconfig.attributes, "OTHER_CPLUSPLUSFLAGS", test_flag) + ReactNativePodsUtils.add_flag_to_map_with_inheritance(twiceProcessed_xcconfig.attributes, "OTHER_CPLUSPLUSFLAGS", test_flag) + + # Assert + assert_equal("$(inherited)" + test_flag, empty_xcconfig.attributes["OTHER_CPLUSPLUSFLAGS"]) + assert_equal("$(inherited) INIT_FLAG" + test_flag, initialized_xcconfig.attributes["OTHER_CPLUSPLUSFLAGS"]) + assert_equal("$(inherited)" + test_flag, twiceProcessed_xcconfig.attributes["OTHER_CPLUSPLUSFLAGS"]) + end + + def test_add_ndebug_flag_to_pods_in_release + # Arrange + xcconfig = XCConfigMock.new("Config") + default_debug_config = BuildConfigurationMock.new("Debug") + default_release_config = BuildConfigurationMock.new("Release") + custom_debug_config1 = BuildConfigurationMock.new("CustomDebug") + custom_debug_config2 = BuildConfigurationMock.new("Custom") + custom_release_config1 = BuildConfigurationMock.new("CustomRelease") + custom_release_config2 = BuildConfigurationMock.new("Production") + + installer = prepare_installer_for_cpp_flags( + [ xcconfig ], + { + "Default" => [ default_debug_config, default_release_config ], + "Custom1" => [ custom_debug_config1, custom_release_config1 ], + "Custom2" => [ custom_debug_config2, custom_release_config2 ] + } + ) + # Act + ReactNativePodsUtils.add_ndebug_flag_to_pods_in_release(installer) + + # Assert + assert_equal(nil, default_debug_config.build_settings["OTHER_CPLUSPLUSFLAGS"]) + assert_equal("$(inherited) -DNDEBUG", default_release_config.build_settings["OTHER_CPLUSPLUSFLAGS"]) + assert_equal(nil, custom_debug_config1.build_settings["OTHER_CPLUSPLUSFLAGS"]) + assert_equal("$(inherited) -DNDEBUG", custom_release_config1.build_settings["OTHER_CPLUSPLUSFLAGS"]) + assert_equal(nil, custom_debug_config2.build_settings["OTHER_CPLUSPLUSFLAGS"]) + assert_equal("$(inherited) -DNDEBUG", custom_release_config2.build_settings["OTHER_CPLUSPLUSFLAGS"]) + end end # ===== # @@ -1112,3 +1123,31 @@ def prepare_Code_Signing_build_configuration(name, param) "CODE_SIGNING_ALLOWED" => param }) end + +def prepare_pod_target_installation_results_mock(name, configs) + target = TargetMock.new(name, configs) + return TargetInstallationResultMock.new(target, target) +end + +def prepare_installer_for_cpp_flags(xcconfigs, build_configs) + xcconfigs_map = {} + xcconfigs.each do |config| + xcconfigs_map[config.name.to_s] = config + end + + pod_target_installation_results_map = {} + build_configs.each do |name, build_configs| + pod_target_installation_results_map[name.to_s] = prepare_pod_target_installation_results_mock( + name.to_s, build_configs + ) + end + + return InstallerMock.new( + PodsProjectMock.new, + [ + AggregatedProjectMock.new(:xcconfigs => xcconfigs_map, :base_path => "a/path/") + ], + :pod_target_installation_results => pod_target_installation_results_map + ) +end + diff --git a/packages/react-native/scripts/cocoapods/codegen.rb b/packages/react-native/scripts/cocoapods/codegen.rb index 7842f39f4226c5..4c1ac3dc6b59e5 100644 --- a/packages/react-native/scripts/cocoapods/codegen.rb +++ b/packages/react-native/scripts/cocoapods/codegen.rb @@ -18,47 +18,7 @@ def build_codegen!(react_native_path, relative_installation_root, dir_manager: D system("#{codegen_repo_path}/scripts/oss/build.sh") end -# It generates an empty `ThirdPartyProvider`, required by Fabric to load the components -# -# Parameters: -# - react_native_path: path to the react native framework -# - new_arch_enabled: whether the New Architecture is enabled or not -# - dir_manager: a class that implements the `Dir` interface. Defaults to `Dir`, the Dependency can be injected for testing purposes. -# - file_manager: a class that implements the `File` interface. Defaults to `File`, the Dependency can be injected for testing purposes. -def checkAndGenerateEmptyThirdPartyProvider!(react_native_path, new_arch_enabled, dir_manager: Dir, file_manager: File) - return if new_arch_enabled - - relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) - - output_dir = "#{relative_installation_root}/#{react_native_path}/React/Fabric" - - provider_h_path = "#{output_dir}/RCTThirdPartyFabricComponentsProvider.h" - provider_cpp_path ="#{output_dir}/RCTThirdPartyFabricComponentsProvider.mm" - - if(!file_manager.exist?(provider_h_path) || !file_manager.exist?(provider_cpp_path)) - # build codegen - build_codegen!(react_native_path, relative_installation_root, dir_manager: dir_manager) - - # Just use a temp empty schema list. - temp_schema_list_path = "#{output_dir}/tmpSchemaList.txt" - file_manager.open(temp_schema_list_path, 'w') do |f| - f.write('[]') - f.fsync - end - - Pod::UI.puts '[Codegen] generating an empty RCTThirdPartyFabricComponentsProvider' - Pod::Executable.execute_command( - 'node', - [ - "#{basePath(react_native_path, relative_installation_root)}/scripts/generate-provider-cli.js", - "--platform", 'ios', - "--schemaListPath", temp_schema_list_path, - "--outputDir", "#{output_dir}" - ]) - file_manager.delete(temp_schema_list_path) if file_manager.exist?(temp_schema_list_path) - end -end - +# keeping the run_codegen! method for testing purposes def run_codegen!( app_path, config_file_dir, @@ -74,28 +34,17 @@ def run_codegen!( codegen_utils: CodegenUtils.new() ) - if new_arch_enabled - codegen_utils.use_react_native_codegen_discovery!( - disable_codegen, - app_path, - :react_native_path => react_native_path, - :fabric_enabled => fabric_enabled, - :hermes_enabled => hermes_enabled, - :config_file_dir => config_file_dir, - :codegen_output_dir => codegen_output_dir, - :config_key => config_key, - :folly_version => folly_version - ) - else - # Generate a podspec file for generated files. - # This gets generated in use_react_native_codegen_discovery when codegen discovery is enabled. - react_codegen_spec = codegen_utils.get_react_codegen_spec( - package_json_file, - :fabric_enabled => fabric_enabled, - :hermes_enabled => hermes_enabled - ) - codegen_utils.generate_react_codegen_podspec!(react_codegen_spec, codegen_output_dir) - end + codegen_utils.use_react_native_codegen_discovery!( + disable_codegen, + app_path, + :react_native_path => react_native_path, + :fabric_enabled => fabric_enabled, + :hermes_enabled => hermes_enabled, + :config_file_dir => config_file_dir, + :codegen_output_dir => codegen_output_dir, + :config_key => config_key, + :folly_version => folly_version + ) end def basePath(react_native_path, relative_installation_root) diff --git a/packages/react-native/scripts/cocoapods/codegen_utils.rb b/packages/react-native/scripts/cocoapods/codegen_utils.rb index a39c77ed9a9611..9875b2646a2bf3 100644 --- a/packages/react-native/scripts/cocoapods/codegen_utils.rb +++ b/packages/react-native/scripts/cocoapods/codegen_utils.rb @@ -66,11 +66,10 @@ def generate_react_codegen_podspec!(spec, codegen_output_dir, file_manager: File # # Parameters # - package_json_file: the path to the `package.json`, required to extract the proper React Native version - # - fabric_enabled: whether fabric is enabled or not. # - hermes_enabled: whether hermes is enabled or not. # - script_phases: whether we want to add some build script phases or not. # - file_manager: a class that implements the `File` interface. Defaults to `File`, the Dependency can be injected for testing purposes. - def get_react_codegen_spec(package_json_file, folly_version: '2023.08.07.00', fabric_enabled: false, hermes_enabled: true, script_phases: nil, file_manager: File) + def get_react_codegen_spec(package_json_file, folly_version: '2023.08.07.00', hermes_enabled: true, script_phases: nil, file_manager: File) package = JSON.parse(file_manager.read(package_json_file)) version = package['version'] new_arch_disabled = ENV['RCT_NEW_ARCH_ENABLED'] != "1" @@ -136,18 +135,14 @@ def get_react_codegen_spec(package_json_file, folly_version: '2023.08.07.00', fa "React-NativeModulesApple": [], "glog": [], "DoubleConversion": [], - } - } - - if fabric_enabled - spec[:'dependencies'].merge!({ 'React-graphics': [], 'React-rendererdebug': [], 'React-Fabric': [], + 'React-FabricImage': [], 'React-debug': [], 'React-utils': [], - }); - end + } + } if hermes_enabled spec[:'dependencies'].merge!({ @@ -159,13 +154,6 @@ def get_react_codegen_spec(package_json_file, folly_version: '2023.08.07.00', fa }); end - if new_arch_disabled - spec[:dependencies].merge!({ - 'React-rncore': [], - 'FBReactNativeSpec': [], - }) - end - if script_phases Pod::UI.puts "[Codegen] Adding script_phases to React-Codegen." spec[:'script_phases'] = script_phases @@ -320,7 +308,6 @@ def use_react_native_codegen_discovery!( react_codegen_spec = codegen_utils.get_react_codegen_spec( file_manager.join(relative_installation_root, react_native_path, "package.json"), :folly_version => folly_version, - :fabric_enabled => fabric_enabled, :hermes_enabled => hermes_enabled, :script_phases => script_phases ) @@ -332,7 +319,6 @@ def use_react_native_codegen_discovery!( "#{relative_installation_root}/#{react_native_path}/scripts/generate-codegen-artifacts.js", "-p", "#{app_path}", "-o", Pod::Config.instance.installation_root, - "-e", "#{fabric_enabled}", "-c", "#{config_file_dir}", ]) Pod::UI.puts out; diff --git a/packages/react-native/scripts/cocoapods/new_architecture.rb b/packages/react-native/scripts/cocoapods/new_architecture.rb index 20ae33fbe87b57..0d2aa46333d3f1 100644 --- a/packages/react-native/scripts/cocoapods/new_architecture.rb +++ b/packages/react-native/scripts/cocoapods/new_architecture.rb @@ -12,7 +12,7 @@ class NewArchitectureHelper @@folly_compiler_flags = "#{@@shared_flags} -Wno-comma -Wno-shorten-64-to-32" - @@new_arch_cpp_flags = "$(inherited) -DRCT_NEW_ARCH_ENABLED=1 #{@@shared_flags}" + @@new_arch_cpp_flags = " -DRCT_NEW_ARCH_ENABLED=1 #{@@shared_flags}" @@cplusplus_version = "c++20" @@ -49,17 +49,10 @@ def self.modify_flags_for_new_architecture(installer, is_new_arch_enabled) unless is_new_arch_enabled return end - ndebug_flag = " -DNDEBUG" # Add RCT_NEW_ARCH_ENABLED to Target pods xcconfig installer.aggregate_targets.each do |aggregate_target| aggregate_target.xcconfigs.each do |config_name, config_file| - config_file.attributes['OTHER_CPLUSPLUSFLAGS'] = @@new_arch_cpp_flags - - if config_name == "Release" - config_file.attributes['OTHER_CPLUSPLUSFLAGS'] = config_file.attributes['OTHER_CPLUSPLUSFLAGS'] + ndebug_flag - other_cflags = config_file.attributes['OTHER_CFLAGS'] != nil ? config_file.attributes['OTHER_CFLAGS'] : "$(inherited)" - config_file.attributes['OTHER_CFLAGS'] = other_cflags + ndebug_flag - end + ReactNativePodsUtils.add_flag_to_map_with_inheritance(config_file.attributes, "OTHER_CPLUSPLUSFLAGS", @@new_arch_cpp_flags) xcconfig_path = aggregate_target.xcconfig_path(config_name) config_file.save_as(xcconfig_path) @@ -71,27 +64,7 @@ def self.modify_flags_for_new_architecture(installer, is_new_arch_enabled) # The React-Core pod may have a suffix added by Cocoapods, so we test whether 'React-Core' is a substring, and do not require exact match if pod_name.include? 'React-Core' target_installation_result.native_target.build_configurations.each do |config| - config.build_settings['OTHER_CPLUSPLUSFLAGS'] = @@new_arch_cpp_flags - end - end - - # Set "RCT_DYNAMIC_FRAMEWORKS=1" if pod are installed with USE_FRAMEWORKS=dynamic - # This helps with backward compatibility. - if pod_name == 'React-RCTFabric' && ENV['USE_FRAMEWORKS'] == 'dynamic' - Pod::UI.puts "Setting -DRCT_DYNAMIC_FRAMEWORKS=1 to React-RCTFabric".green - rct_dynamic_framework_flag = " -DRCT_DYNAMIC_FRAMEWORKS=1" - target_installation_result.native_target.build_configurations.each do |config| - prev_build_settings = config.build_settings['OTHER_CPLUSPLUSFLAGS'] != nil ? config.build_settings['OTHER_CPLUSPLUSFLAGS'] : "$(inherithed)" - config.build_settings['OTHER_CPLUSPLUSFLAGS'] = prev_build_settings + rct_dynamic_framework_flag - end - end - - target_installation_result.native_target.build_configurations.each do |config| - if config.name == "Release" - current_flags = config.build_settings['OTHER_CPLUSPLUSFLAGS'] != nil ? config.build_settings['OTHER_CPLUSPLUSFLAGS'] : "$(inherited)" - config.build_settings['OTHER_CPLUSPLUSFLAGS'] = current_flags + ndebug_flag - current_cflags = config.build_settings['OTHER_CFLAGS'] != nil ? config.build_settings['OTHER_CFLAGS'] : "$(inherited)" - config.build_settings['OTHER_CFLAGS'] = current_cflags + ndebug_flag + ReactNativePodsUtils.add_flag_to_map_with_inheritance(config.build_settings, "OTHER_CPLUSPLUSFLAGS", @@new_arch_cpp_flags) end end end @@ -137,28 +110,29 @@ def self.install_modules_dependencies(spec, new_arch_enabled, folly_version) spec.dependency "glog" if new_arch_enabled - current_config["OTHER_CPLUSPLUSFLAGS"] = @@new_arch_cpp_flags - spec.dependency "React-RCTFabric" # This is for Fabric Component - spec.dependency "React-Codegen" - - spec.dependency "RCTRequired" - spec.dependency "RCTTypeSafety" - spec.dependency "ReactCommon/turbomodule/bridging" - spec.dependency "ReactCommon/turbomodule/core" - spec.dependency "React-NativeModulesApple" - spec.dependency "Yoga" - spec.dependency "React-Fabric" - spec.dependency "React-graphics" - spec.dependency "React-utils" - spec.dependency "React-debug" - spec.dependency "React-ImageManager" - spec.dependency "React-rendererdebug" - - if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1" - spec.dependency "hermes-engine" - else - spec.dependency "React-jsi" - end + ReactNativePodsUtils.add_flag_to_map_with_inheritance(current_config, "OTHER_CPLUSPLUSFLAGS", @@new_arch_cpp_flags) + end + + spec.dependency "React-RCTFabric" # This is for Fabric Component + spec.dependency "React-Codegen" + + spec.dependency "RCTRequired" + spec.dependency "RCTTypeSafety" + spec.dependency "ReactCommon/turbomodule/bridging" + spec.dependency "ReactCommon/turbomodule/core" + spec.dependency "React-NativeModulesApple" + spec.dependency "Yoga" + spec.dependency "React-Fabric" + spec.dependency "React-graphics" + spec.dependency "React-utils" + spec.dependency "React-debug" + spec.dependency "React-ImageManager" + spec.dependency "React-rendererdebug" + + if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1" + spec.dependency "hermes-engine" + else + spec.dependency "React-jsi" end spec.pod_target_xcconfig = current_config diff --git a/packages/react-native/scripts/cocoapods/utils.rb b/packages/react-native/scripts/cocoapods/utils.rb index 4a8bd34d71e039..ace3848aa849d7 100644 --- a/packages/react-native/scripts/cocoapods/utils.rb +++ b/packages/react-native/scripts/cocoapods/utils.rb @@ -147,15 +147,6 @@ def self.apply_xcode_15_patch(installer, xcodebuild_manager: Xcodebuild) end - def self.apply_flags_for_fabric(installer, fabric_enabled: false) - fabric_flag = "-DRN_FABRIC_ENABLED" - if fabric_enabled - self.add_compiler_flag_to_project(installer, fabric_flag) - else - self.remove_compiler_flag_from_project(installer, fabric_flag) - end - end - private def self.add_build_settings_to_pod(installer, settings_name, settings_value, target_pod_name, configuration) @@ -318,6 +309,22 @@ def self.updateOSDeploymentTarget(installer) end end + def self.set_dynamic_frameworks_flags(installer) + installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result| + + # Set "RCT_DYNAMIC_FRAMEWORKS=1" if pod are installed with USE_FRAMEWORKS=dynamic + # This helps with backward compatibility. + if pod_name == 'React-RCTFabric' && ENV['USE_FRAMEWORKS'] == 'dynamic' + Pod::UI.puts "Setting -DRCT_DYNAMIC_FRAMEWORKS=1 to React-RCTFabric".green + rct_dynamic_framework_flag = " -DRCT_DYNAMIC_FRAMEWORKS=1" + target_installation_result.native_target.build_configurations.each do |config| + prev_build_settings = config.build_settings['OTHER_CPLUSPLUSFLAGS'] != nil ? config.build_settings['OTHER_CPLUSPLUSFLAGS'] : "$(inherithed)" + config.build_settings['OTHER_CPLUSPLUSFLAGS'] = prev_build_settings + rct_dynamic_framework_flag + end + end + end + end + # ========= # # Utilities # # ========= # @@ -606,4 +613,46 @@ def self.add_search_path_to_result(result, base_path, additional_paths, include_ } return result end + + def self.add_ndebug_flag_to_pods_in_release(installer) + ndebug_flag = " -DNDEBUG" + + installer.aggregate_targets.each do |aggregate_target| + aggregate_target.xcconfigs.each do |config_name, config_file| + is_release = config_name.downcase.include?("release") || config_name.downcase.include?("production") + unless is_release + next + end + self.add_flag_to_map_with_inheritance(config_file.attributes, 'OTHER_CPLUSPLUSFLAGS', ndebug_flag); + self.add_flag_to_map_with_inheritance(config_file.attributes, 'OTHER_CFLAGS', ndebug_flag); + + xcconfig_path = aggregate_target.xcconfig_path(config_name) + config_file.save_as(xcconfig_path) + end + end + + installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result| + target_installation_result.native_target.build_configurations.each do |config| + is_release = config.name.downcase.include?("release") || config.name.downcase.include?("production") + unless is_release + next + end + self.add_flag_to_map_with_inheritance(config.build_settings, 'OTHER_CPLUSPLUSFLAGS', ndebug_flag); + self.add_flag_to_map_with_inheritance(config.build_settings, 'OTHER_CFLAGS', ndebug_flag); + end + end + end + + def self.add_flag_to_map_with_inheritance(map, field, flag) + if map[field] == nil + map[field] = "$(inherited)" + flag + else + unless map[field].include?(flag) + map[field] = map[field] + flag + end + unless map[field].include?("$(inherited)") + map[field] = "$(inherited) " + map[field] + end + end + end end diff --git a/packages/react-native/scripts/codegen/__tests__/generate-artifacts-executor-test.js b/packages/react-native/scripts/codegen/__tests__/generate-artifacts-executor-test.js index 703a210f99a6b2..79fa376c6ade0b 100644 --- a/packages/react-native/scripts/codegen/__tests__/generate-artifacts-executor-test.js +++ b/packages/react-native/scripts/codegen/__tests__/generate-artifacts-executor-test.js @@ -12,115 +12,16 @@ const fixtures = require('../__test_fixtures__/fixtures'); const underTest = require('../generate-artifacts-executor'); -const child_process = require('child_process'); -const fs = require('fs'); const path = require('path'); -const codegenConfigKey = 'codegenConfig'; -const reactNativeDependencyName = 'react-native'; const rootPath = path.join(__dirname, '../../..'); -describe('generateCode', () => { - afterEach(() => { - jest.resetModules(); - jest.resetAllMocks(); - }); - - beforeEach(() => { - // Silence logs from printDeprecationWarningIfNeeded. Ideally, we should have test assertions on these warnings. - jest.spyOn(console, 'log').mockImplementation(); - jest.spyOn(console, 'debug').mockImplementation(); - }); - - it('executeNodes with the right arguments', () => { - // Define variables and expected values - const iosOutputDir = 'app/ios/build/generated/ios'; - const library = {config: {name: 'library', type: 'all'}}; - const tmpDir = 'tmp'; - const node = 'usr/bin/node'; - const pathToSchema = 'app/build/schema.json'; - const rnRoot = path.join(__dirname, '../..'); - const libraryTypeArg = 'all'; - - const tmpOutputDir = path.join(tmpDir, 'out'); - - // mock used functions - jest.spyOn(fs, 'mkdirSync').mockImplementation(); - jest.spyOn(child_process, 'execSync').mockImplementation(); - jest.spyOn(child_process, 'execFileSync').mockImplementation(); - - underTest._generateCode(iosOutputDir, library, tmpDir, node, pathToSchema); - - expect(child_process.execFileSync).toHaveBeenCalledTimes(1); - expect(child_process.execFileSync).toHaveBeenNthCalledWith(1, node, [ - `${path.join(rnRoot, 'generate-specs-cli.js')}`, - '--platform', - 'ios', - '--schemaPath', - pathToSchema, - '--outputDir', - tmpOutputDir, - '--libraryName', - library.config.name, - '--libraryType', - libraryTypeArg, - ]); - expect(child_process.execSync).toHaveBeenCalledTimes(1); - expect(child_process.execSync).toHaveBeenNthCalledWith( - 1, - `cp -R ${tmpOutputDir}/* "${iosOutputDir}"`, - ); - - expect(fs.mkdirSync).toHaveBeenCalledTimes(2); - expect(fs.mkdirSync).toHaveBeenNthCalledWith(1, tmpOutputDir, { - recursive: true, - }); - expect(fs.mkdirSync).toHaveBeenNthCalledWith(2, iosOutputDir, { - recursive: true, - }); - }); -}); - describe('extractLibrariesFromJSON', () => { - it('throws if in react-native and no dependencies found', () => { - let libraries = []; - let configFile = {}; - expect(() => { - underTest._extractLibrariesFromJSON( - configFile, - libraries, - codegenConfigKey, - ); - }).toThrow(); - }); - - it('it skips if not into react-native and no dependencies found', () => { - let libraries = []; - let configFile = {}; - - underTest._extractLibrariesFromJSON( - configFile, - libraries, - codegenConfigKey, - 'some-node-module', - 'node_modules/some', - ); - expect(libraries.length).toBe(0); - }); - it('extracts a single dependency when config has no libraries', () => { - let libraries = []; let configFile = fixtures.noLibrariesConfigFile; - underTest._extractLibrariesFromJSON( - configFile, - libraries, - codegenConfigKey, - 'my-app', - '.', - ); + let libraries = underTest._extractLibrariesFromJSON(configFile, '.'); expect(libraries.length).toBe(1); expect(libraries[0]).toEqual({ - library: 'my-app', config: { name: 'AppModules', type: 'all', @@ -130,32 +31,17 @@ describe('extractLibrariesFromJSON', () => { }); }); - it("extract codegenConfig when it's empty", () => { + it("doesn't extract libraries when they are present but empty", () => { const configFile = {codegenConfig: {libraries: []}}; - let libraries = []; - underTest._extractLibrariesFromJSON( - configFile, - codegenConfigKey, - libraries, - reactNativeDependencyName, - rootPath, - ); + let libraries = underTest._extractLibrariesFromJSON(configFile, rootPath); expect(libraries.length).toBe(0); }); - it('extract codegenConfig when dependency is one', () => { + it('extracts libraries when they are present and not empty', () => { const configFile = fixtures.singleLibraryCodegenConfig; - let libraries = []; - underTest._extractLibrariesFromJSON( - configFile, - libraries, - codegenConfigKey, - reactNativeDependencyName, - rootPath, - ); + let libraries = underTest._extractLibrariesFromJSON(configFile, rootPath); expect(libraries.length).toBe(1); expect(libraries[0]).toEqual({ - library: reactNativeDependencyName, config: { name: 'react-native', type: 'all', @@ -169,17 +55,12 @@ describe('extractLibrariesFromJSON', () => { const configFile = fixtures.multipleLibrariesCodegenConfig; const myDependency = 'my-dependency'; const myDependencyPath = path.join(__dirname, myDependency); - let libraries = []; - underTest._extractLibrariesFromJSON( + let libraries = underTest._extractLibrariesFromJSON( configFile, - libraries, - codegenConfigKey, - myDependency, myDependencyPath, ); expect(libraries.length).toBe(3); expect(libraries[0]).toEqual({ - library: myDependency, config: { name: 'react-native', type: 'all', @@ -188,7 +69,6 @@ describe('extractLibrariesFromJSON', () => { libraryPath: myDependencyPath, }); expect(libraries[1]).toEqual({ - library: myDependency, config: { name: 'my-component', type: 'components', @@ -197,7 +77,6 @@ describe('extractLibrariesFromJSON', () => { libraryPath: myDependencyPath, }); expect(libraries[2]).toEqual({ - library: myDependency, config: { name: 'my-module', type: 'module', @@ -208,83 +87,6 @@ describe('extractLibrariesFromJSON', () => { }); }); -describe('findCodegenEnabledLibraries', () => { - const mock = require('mock-fs'); - const { - _findCodegenEnabledLibraries: findCodegenEnabledLibraries, - } = require('../generate-artifacts-executor'); - - afterEach(() => { - mock.restore(); - }); - - it('returns libraries defined in react-native.config.js', () => { - const projectDir = path.join(__dirname, '../../../../test-project'); - const baseCodegenConfigFileDir = path.join(__dirname, '../../..'); - const baseCodegenConfigFilePath = path.join( - baseCodegenConfigFileDir, - 'package.json', - ); - - mock({ - [baseCodegenConfigFilePath]: ` - { - "codegenConfig": {} - } - `, - [projectDir]: { - app: { - 'package.json': `{ - "name": "my-app" - }`, - 'react-native.config.js': '', - }, - 'library-foo': { - 'package.json': `{ - "name": "react-native-foo", - "codegenConfig": { - "name": "RNFooSpec", - "type": "modules", - "jsSrcsDir": "src" - } - }`, - }, - }, - }); - - jest.mock(path.join(projectDir, 'app', 'react-native.config.js'), () => ({ - dependencies: { - 'react-native-foo': { - root: path.join(projectDir, 'library-foo'), - }, - 'react-native-bar': { - root: path.join(projectDir, 'library-bar'), - }, - }, - })); - - const libraries = findCodegenEnabledLibraries( - `${projectDir}/app`, - baseCodegenConfigFileDir, - `package.json`, - 'codegenConfig', - ); - - expect(libraries).toEqual([ - { - library: 'react-native', - config: {}, - libraryPath: baseCodegenConfigFileDir, - }, - { - library: 'react-native-foo', - config: {name: 'RNFooSpec', type: 'modules', jsSrcsDir: 'src'}, - libraryPath: path.join(projectDir, 'library-foo'), - }, - ]); - }); -}); - describe('delete empty files and folders', () => { beforeEach(() => { jest.resetModules(); diff --git a/packages/react-native/scripts/codegen/codegen-utils.js b/packages/react-native/scripts/codegen/codegen-utils.js index b739d81c5a4075..d151bda6eff5c2 100644 --- a/packages/react-native/scripts/codegen/codegen-utils.js +++ b/packages/react-native/scripts/codegen/codegen-utils.js @@ -32,6 +32,20 @@ function getCodegen() { return RNCodegen; } +function getCombineJSToSchema() { + let combineJSToSchema; + try { + combineJSToSchema = require('../../packages/react-native-codegen/lib/cli/combine/combine-js-to-schema.js'); + } catch (e) { + combineJSToSchema = require('@react-native/codegen/lib/cli/combine/combine-js-to-schema.js'); + } + if (!combineJSToSchema) { + throw 'combine-js-to-schema not found.'; + } + return combineJSToSchema; +} + module.exports = { getCodegen: getCodegen, + getCombineJSToSchema: getCombineJSToSchema, }; diff --git a/packages/react-native/scripts/codegen/generate-artifacts-executor.js b/packages/react-native/scripts/codegen/generate-artifacts-executor.js index dc8a5bab381212..e0b7c0dd56bb33 100644 --- a/packages/react-native/scripts/codegen/generate-artifacts-executor.js +++ b/packages/react-native/scripts/codegen/generate-artifacts-executor.js @@ -12,12 +12,15 @@ /** * This script crawls through a React Native application's dependencies and invokes the codegen * for any libraries that require it. - * To enable codegen support, the library should include a config in the codegenConfigKey key - * in a codegenConfigFilename file. + * To enable codegen support, the library should include a config in the codegenConfig key + * in a package.json file. */ -const {execFileSync, execSync} = require('child_process'); +const utils = require('./codegen-utils'); +const generateSpecsCLIExecutor = require('./generate-specs-cli-executor'); +const {execSync} = require('child_process'); const fs = require('fs'); +const mkdirp = require('mkdirp'); const os = require('os'); const path = require('path'); @@ -29,15 +32,12 @@ const REACT_NATIVE_REPOSITORY_ROOT = path.join( '..', ); const REACT_NATIVE_PACKAGE_ROOT_FOLDER = path.join(__dirname, '..', '..'); - -const CODEGEN_DEPENDENCY_NAME = '@react-native/codegen'; const CODEGEN_REPO_PATH = `${REACT_NATIVE_REPOSITORY_ROOT}/packages/react-native-codegen`; -const CODEGEN_NPM_PATH = `${REACT_NATIVE_PACKAGE_ROOT_FOLDER}/../${CODEGEN_DEPENDENCY_NAME}`; const CORE_LIBRARIES_WITH_OUTPUT_FOLDER = { rncore: path.join(REACT_NATIVE_PACKAGE_ROOT_FOLDER, 'ReactCommon'), FBReactNativeSpec: null, }; -const REACT_NATIVE_DEPENDENCY_NAME = 'react-native'; +const REACT_NATIVE = 'react-native'; // HELPERS @@ -45,25 +45,16 @@ function isReactNativeCoreLibrary(libraryName) { return libraryName in CORE_LIBRARIES_WITH_OUTPUT_FOLDER; } -function executeNodeScript(node, scriptArgs) { - execFileSync(node, scriptArgs); -} - -function isAppRootValid(appRootDir) { - if (appRootDir == null) { - console.error('Missing path to React Native application'); - process.exitCode = 1; - return false; +function readPkgJsonInDirectory(dir) { + const pkgJsonPath = path.join(dir, 'package.json'); + if (!fs.existsSync(pkgJsonPath)) { + throw `[Codegen] Error: ${pkgJsonPath} does not exist.`; } - return true; -} - -function readPackageJSON(appRootDir) { - return JSON.parse(fs.readFileSync(path.join(appRootDir, 'package.json'))); + return JSON.parse(fs.readFileSync(pkgJsonPath)); } function printDeprecationWarningIfNeeded(dependency) { - if (dependency === REACT_NATIVE_DEPENDENCY_NAME) { + if (dependency === REACT_NATIVE) { return; } console.log(`[Codegen] CodegenConfig Deprecated Setup for ${dependency}. @@ -101,384 +92,184 @@ function printDeprecationWarningIfNeeded(dependency) { } // Reading Libraries -function extractLibrariesFromConfigurationArray( - configFile, - codegenConfigKey, - libraries, - dependency, - dependencyPath, -) { - console.log(`[Codegen] Found ${dependency}`); - configFile[codegenConfigKey].libraries.forEach(config => { - const libraryConfig = { - library: dependency, +function extractLibrariesFromConfigurationArray(configFile, dependencyPath) { + return configFile.codegenConfig.libraries.map(config => { + return { config, libraryPath: dependencyPath, }; - libraries.push(libraryConfig); }); } -function extractLibrariesFromJSON( - configFile, - libraries, - codegenConfigKey, - dependency, - dependencyPath, -) { - var isBlocking = false; - if (dependency == null) { - dependency = REACT_NATIVE_DEPENDENCY_NAME; - dependencyPath = REACT_NATIVE_PACKAGE_ROOT_FOLDER; - // If we are exploring the ReactNative libraries, we want to raise an error - // if the codegen is not properly configured. - isBlocking = true; - } - - if (configFile[codegenConfigKey] == null) { - if (isBlocking) { - throw `[Codegen] Error: Could not find codegen config for ${dependency} .`; - } - return; +function extractLibrariesFromJSON(configFile, dependencyPath) { + if (configFile.codegenConfig == null) { + return []; } - - if (configFile[codegenConfigKey].libraries == null) { - console.log(`[Codegen] Found ${dependency}`); - var config = configFile[codegenConfigKey]; - libraries.push({ - library: dependency, - config, - libraryPath: dependencyPath, - }); + console.log(`[Codegen] Found ${configFile.name}`); + if (configFile.codegenConfig.libraries == null) { + const config = configFile.codegenConfig; + return [ + { + config, + libraryPath: dependencyPath, + }, + ]; } else { - printDeprecationWarningIfNeeded(dependency); - extractLibrariesFromConfigurationArray( - configFile, - codegenConfigKey, - libraries, - dependency, - dependencyPath, - ); + printDeprecationWarningIfNeeded(configFile.name); + return extractLibrariesFromConfigurationArray(configFile, dependencyPath); } } -function handleReactNativeCodeLibraries( - libraries, - codegenConfigFilename, - codegenConfigKey, -) { - // Handle react-native core libraries. - // This is required when react-native is outside of node_modules. - console.log('[Codegen] Processing react-native core libraries'); - const reactNativePkgJson = path.join( - REACT_NATIVE_PACKAGE_ROOT_FOLDER, - codegenConfigFilename, - ); - if (!fs.existsSync(reactNativePkgJson)) { - throw '[Codegen] Error: Could not find config file for react-native.'; - } - const reactNativeConfigFile = JSON.parse(fs.readFileSync(reactNativePkgJson)); - extractLibrariesFromJSON(reactNativeConfigFile, libraries, codegenConfigKey); -} - -function handleThirdPartyLibraries( - libraries, - baseCodegenConfigFileDir, - dependencies, - codegenConfigFilename, - codegenConfigKey, -) { +function findExternalLibraries(pkgJson) { + const dependencies = { + ...pkgJson.dependencies, + ...pkgJson.devDependencies, + ...pkgJson.peerDependencies, + }; // Determine which of these are codegen-enabled libraries - const configDir = - baseCodegenConfigFileDir || - path.join(REACT_NATIVE_PACKAGE_ROOT_FOLDER, '..'); console.log( - `\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in ${configDir}`, + '\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in the project dependencies.', ); - // Handle third-party libraries - Object.keys(dependencies).forEach(dependency => { - if (dependency === REACT_NATIVE_DEPENDENCY_NAME) { - // react-native should already be added. - return; - } - const codegenConfigFileDir = path.join(configDir, dependency); - const configFilePath = path.join( - codegenConfigFileDir, - codegenConfigFilename, - ); - if (fs.existsSync(configFilePath)) { - const configFile = JSON.parse(fs.readFileSync(configFilePath)); - extractLibrariesFromJSON( - configFile, - libraries, - codegenConfigKey, - dependency, - codegenConfigFileDir, + return Object.keys(dependencies).flatMap(dependency => { + try { + const configFilePath = require.resolve( + path.join(dependency, 'package.json'), ); + const configFile = JSON.parse(fs.readFileSync(configFilePath)); + const codegenConfigFileDir = path.dirname(configFilePath); + return extractLibrariesFromJSON(configFile, codegenConfigFileDir); + } catch (e) { + return []; } }); } -function handleLibrariesFromReactNativeConfig( - libraries, - codegenConfigKey, - codegenConfigFilename, - appRootDir, -) { - const rnConfigFileName = 'react-native.config.js'; - - console.log( - `\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in ${rnConfigFileName}`, - ); - - const rnConfigFilePath = path.resolve(appRootDir, rnConfigFileName); - - if (fs.existsSync(rnConfigFilePath)) { - const rnConfig = require(rnConfigFilePath); - - if (rnConfig.dependencies != null) { - Object.keys(rnConfig.dependencies).forEach(name => { - const dependencyConfig = rnConfig.dependencies[name]; - - if (dependencyConfig.root) { - const codegenConfigFileDir = path.resolve( - appRootDir, - dependencyConfig.root, - ); - const configFilePath = path.join( - codegenConfigFileDir, - codegenConfigFilename, - ); - const pkgJsonPath = path.join(codegenConfigFileDir, 'package.json'); - - if (fs.existsSync(configFilePath)) { - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath)); - const configFile = JSON.parse(fs.readFileSync(configFilePath)); - extractLibrariesFromJSON( - configFile, - libraries, - codegenConfigKey, - pkgJson.name, - codegenConfigFileDir, - ); - } - } - }); - } - } -} - -function handleInAppLibraries( - libraries, - pkgJson, - codegenConfigKey, - appRootDir, -) { +function findProjectRootLibraries(pkgJson, projectRoot) { console.log( '\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in the app', ); - extractLibrariesFromJSON( - pkgJson, - libraries, - codegenConfigKey, - pkgJson.name, - appRootDir, - ); + return extractLibrariesFromJSON(pkgJson, projectRoot); } // CodeGen -function getCodeGenCliPath() { - let codegenCliPath; - if (fs.existsSync(CODEGEN_REPO_PATH)) { - codegenCliPath = CODEGEN_REPO_PATH; - - if (!fs.existsSync(path.join(CODEGEN_REPO_PATH, 'lib'))) { - console.log('\n\n[Codegen] >>>>> Building react-native-codegen package'); - execSync('yarn install', { - cwd: codegenCliPath, - stdio: 'inherit', - }); - execSync('yarn build', { - cwd: codegenCliPath, - stdio: 'inherit', - }); - } - } else if (fs.existsSync(CODEGEN_NPM_PATH)) { - codegenCliPath = CODEGEN_NPM_PATH; - } else { - throw `error: Could not determine ${CODEGEN_DEPENDENCY_NAME} location. Try running 'yarn install' or 'npm install' in your project root.`; +function buildCodegenIfNeeded() { + if (!fs.existsSync(CODEGEN_REPO_PATH)) { + return; + } + // Assuming we are working in the react-native repo. We might need to build the codegen. + // This will become unnecessary once we start using Babel Register for the codegen package. + const libPath = path.join(CODEGEN_REPO_PATH, 'lib'); + if (fs.existsSync(libPath) && fs.readdirSync(libPath).length > 0) { + return; } - return codegenCliPath; + console.log('\n\n[Codegen] >>>>> Building react-native-codegen package'); + execSync('yarn install', { + cwd: CODEGEN_REPO_PATH, + stdio: 'inherit', + }); + execSync('yarn build', { + cwd: CODEGEN_REPO_PATH, + stdio: 'inherit', + }); } -function computeIOSOutputDir(outputPath, appRootDir) { - return path.join(outputPath ? outputPath : appRootDir, 'build/generated/ios'); +function computeIOSOutputDir(outputPath, projectRoot) { + return path.join( + outputPath ? outputPath : projectRoot, + 'build/generated/ios', + ); } -function generateSchema(tmpDir, library, node, codegenCliPath) { - const pathToSchema = path.join(tmpDir, 'schema.json'); +function generateSchemaInfo(library) { const pathToJavaScriptSources = path.join( library.libraryPath, library.config.jsSrcsDir, ); - console.log(`\n\n[Codegen] >>>>> Processing ${library.config.name}`); // Generate one schema for the entire library... - executeNodeScript(node, [ - `${path.join( - codegenCliPath, - 'lib', - 'cli', - 'combine', - 'combine-js-to-schema-cli.js', - )}`, - '--platform', - 'ios', - pathToSchema, - pathToJavaScriptSources, - ]); - console.log(`[Codegen] Generated schema: ${pathToSchema}`); - return pathToSchema; + return { + library: library, + schema: utils + .getCombineJSToSchema() + .combineSchemasInFileList( + [pathToJavaScriptSources], + 'ios', + /NativeSampleTurboModule/, + ), + }; } -function generateCode(iosOutputDir, library, tmpDir, node, pathToSchema) { - // ...then generate native code artifacts. - const libraryTypeArg = library.config.type ? `${library.config.type}` : ''; - +function generateCode(iosOutputDir, schemaInfo) { + const tmpDir = fs.mkdtempSync( + path.join(os.tmpdir(), schemaInfo.library.config.name), + ); const tmpOutputDir = path.join(tmpDir, 'out'); fs.mkdirSync(tmpOutputDir, {recursive: true}); - executeNodeScript(node, [ - `${path.join( - REACT_NATIVE_PACKAGE_ROOT_FOLDER, - 'scripts', - 'generate-specs-cli.js', - )}`, - '--platform', + generateSpecsCLIExecutor.generateSpecFromInMemorySchema( 'ios', - '--schemaPath', - pathToSchema, - '--outputDir', + schemaInfo.schema, tmpOutputDir, - '--libraryName', - library.config.name, - '--libraryType', - libraryTypeArg, - ]); + schemaInfo.library.config.name, + 'com.facebook.fbreact.specs', + schemaInfo.library.config.type, + ); // Finally, copy artifacts to the final output directory. const outputDir = - CORE_LIBRARIES_WITH_OUTPUT_FOLDER[library.config.name] ?? iosOutputDir; + CORE_LIBRARIES_WITH_OUTPUT_FOLDER[schemaInfo.library.config.name] ?? + iosOutputDir; fs.mkdirSync(outputDir, {recursive: true}); + // TODO: Fix this. This will not work on Windows. execSync(`cp -R ${tmpOutputDir}/* "${outputDir}"`); - console.log(`[Codegen] Generated artifacts: ${iosOutputDir}`); + console.log(`[Codegen] Generated artifacts: ${outputDir}`); } -function generateNativeCodegenFiles( - libraries, - fabricEnabled, - iosOutputDir, - node, - codegenCliPath, - schemaPaths, -) { - let fabricEnabledTypes = ['components', 'all']; - libraries.forEach(library => { - if ( - !fabricEnabled && - fabricEnabledTypes.indexOf(library.config.type) >= 0 - ) { - console.log( - `[Codegen] ${library.config.name} skipped because fabric is not enabled.`, - ); - return; - } - const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), library.config.name)); - const pathToSchema = generateSchema(tmpDir, library, node, codegenCliPath); - generateCode(iosOutputDir, library, tmpDir, node, pathToSchema); - - // Filter the react native core library out. - // In the future, core library and third party library should - // use the same way to generate/register the fabric components. - if (!isReactNativeCoreLibrary(library.config.name)) { - schemaPaths[library.config.name] = pathToSchema; - } +function generateSchemaInfos(libraries) { + return libraries.map(generateSchemaInfo); +} + +function generateNativeCode(iosOutputDir, schemaInfos) { + return schemaInfos.map(schemaInfo => { + generateCode(iosOutputDir, schemaInfo); }); } -function createComponentProvider( - fabricEnabled, - schemaPaths, - node, - iosOutputDir, -) { - if (fabricEnabled) { - console.log('\n\n>>>>> Creating component provider'); - // Save the list of spec paths to a temp file. - const schemaListTmpPath = `${os.tmpdir()}/rn-tmp-schema-list.json`; - const fd = fs.openSync(schemaListTmpPath, 'w'); - fs.writeSync(fd, JSON.stringify(schemaPaths)); - fs.closeSync(fd); - console.log(`Generated schema list: ${schemaListTmpPath}`); - - const outputDir = path.join( - REACT_NATIVE_PACKAGE_ROOT_FOLDER, - 'React', - 'Fabric', - ); - - // Generate FabricComponentProvider. - // Only for iOS at this moment. - executeNodeScript(node, [ - `${path.join( - REACT_NATIVE_PACKAGE_ROOT_FOLDER, - 'scripts', - 'generate-provider-cli.js', - )}`, - '--platform', - 'ios', - '--schemaListPath', - schemaListTmpPath, - '--outputDir', - outputDir, - ]); - console.log(`Generated provider in: ${outputDir}`); - } +function needsThirdPartyComponentProvider(schemaInfo) { + // Filter the react native core library out. + // In the future, core library and third party library should + // use the same way to generate/register the fabric components. + return !isReactNativeCoreLibrary(schemaInfo.library.config.name); } -function findCodegenEnabledLibraries( - appRootDir, - baseCodegenConfigFileDir, - codegenConfigFilename, - codegenConfigKey, -) { - const pkgJson = readPackageJSON(appRootDir); - const dependencies = {...pkgJson.dependencies, ...pkgJson.devDependencies}; - const libraries = []; - - handleReactNativeCodeLibraries( - libraries, - codegenConfigFilename, - codegenConfigKey, - ); - handleThirdPartyLibraries( - libraries, - baseCodegenConfigFileDir, - dependencies, - codegenConfigFilename, - codegenConfigKey, +function createComponentProvider(schemas) { + console.log('\n\n>>>>> Creating component provider'); + const outputDir = path.join( + REACT_NATIVE_PACKAGE_ROOT_FOLDER, + 'React', + 'Fabric', ); - handleLibrariesFromReactNativeConfig( - libraries, - codegenConfigKey, - codegenConfigFilename, - appRootDir, + mkdirp.sync(outputDir); + utils.getCodegen().generateFromSchemas( + { + schemas: schemas, + outputDirectory: outputDir, + }, + { + generators: ['providerIOS'], + }, ); - handleInAppLibraries(libraries, pkgJson, codegenConfigKey, appRootDir); + console.log(`Generated provider in: ${outputDir}`); +} - return libraries; +function findCodegenEnabledLibraries(projectRoot) { + const pkgJson = readPkgJsonInDirectory(projectRoot); + return [ + ...findExternalLibraries(pkgJson), + ...findProjectRootLibraries(pkgJson, projectRoot), + ]; } // It removes all the empty files and empty folders @@ -523,59 +314,32 @@ function cleanupEmptyFilesAndFolders(filepath) { * - setups the CLI to generate the code * - generate the code * - * @parameter appRootDir: the directory with the app source code, where the `codegenConfigFilename` lives. + * @parameter projectRoot: the directory with the app source code, where the package.json lives. * @parameter outputPath: the base output path for the CodeGen. - * @parameter node: the path to the node executable, used to run the codegen scripts. - * @parameter codegenConfigFilename: the file that contains the codeGen configuration. The default is `package.json`. - * @parameter codegenConfigKey: the key in the codegenConfigFile that controls the codegen. - * @parameter baseCodegenConfigFileDir: the directory of the codeGenConfigFile. - * @parameter fabricEnabled: whether fabric is enabled or not. * @throws If it can't find a config file for react-native. * @throws If it can't find a CodeGen configuration in the file. * @throws If it can't find a cli for the CodeGen. */ -function execute( - appRootDir, - outputPath, - node, - codegenConfigFilename, - codegenConfigKey, - baseCodegenConfigFileDir, - fabricEnabled, -) { - if (!isAppRootValid(appRootDir)) { - return; - } +function execute(projectRoot, outputPath) { + buildCodegenIfNeeded(); try { - const libraries = findCodegenEnabledLibraries( - appRootDir, - baseCodegenConfigFileDir, - codegenConfigFilename, - codegenConfigKey, - ); + const libraries = findCodegenEnabledLibraries(projectRoot); if (libraries.length === 0) { console.log('[Codegen] No codegen-enabled libraries found.'); return; } - const codegenCliPath = getCodeGenCliPath(); - - const schemaPaths = {}; - - const iosOutputDir = computeIOSOutputDir(outputPath, appRootDir); + const iosOutputDir = computeIOSOutputDir(outputPath, projectRoot); - generateNativeCodegenFiles( - libraries, - fabricEnabled, - iosOutputDir, - node, - codegenCliPath, - schemaPaths, - ); + const schemaInfos = generateSchemaInfos(libraries); + generateNativeCode(iosOutputDir, schemaInfos); - createComponentProvider(fabricEnabled, schemaPaths, node, iosOutputDir); + const schemas = schemaInfos + .filter(needsThirdPartyComponentProvider) + .map(schemaInfo => schemaInfo.schema); + createComponentProvider(schemas); cleanupEmptyFilesAndFolders(iosOutputDir); } catch (err) { console.error(err); @@ -590,8 +354,5 @@ module.exports = { execute: execute, // exported for testing purposes only: _extractLibrariesFromJSON: extractLibrariesFromJSON, - _findCodegenEnabledLibraries: findCodegenEnabledLibraries, - _executeNodeScript: executeNodeScript, - _generateCode: generateCode, _cleanupEmptyFilesAndFolders: cleanupEmptyFilesAndFolders, }; diff --git a/packages/react-native/scripts/codegen/generate-specs-cli-executor.js b/packages/react-native/scripts/codegen/generate-specs-cli-executor.js index 3f4f93cdc1c812..fb88e4a1dd54d2 100644 --- a/packages/react-native/scripts/codegen/generate-specs-cli-executor.js +++ b/packages/react-native/scripts/codegen/generate-specs-cli-executor.js @@ -13,7 +13,6 @@ const utils = require('./codegen-utils'); const fs = require('fs'); const mkdirp = require('mkdirp'); const path = require('path'); -const RNCodegen = utils.getCodegen(); const GENERATORS = { all: { @@ -71,18 +70,15 @@ function validateLibraryType(libraryType) { } } -function generateSpec( +function generateSpecFromInMemorySchema( platform, - schemaPath, + schema, outputDirectory, libraryName, packageName, libraryType, ) { validateLibraryType(libraryType); - - let schema = readAndParseSchema(schemaPath); - createOutputDirectoryIfNeeded(outputDirectory, libraryName); function composePath(intermediate) { return path.join(outputDirectory, intermediate, libraryName); @@ -94,7 +90,7 @@ function generateSpec( createFolderIfDefined(composePath('react/renderer/components/')); createFolderIfDefined(composePath('./')); - RNCodegen.generate( + utils.getCodegen().generate( { libraryName, schema, @@ -122,6 +118,25 @@ function generateSpec( } } +function generateSpec( + platform, + schemaPath, + outputDirectory, + libraryName, + packageName, + libraryType, +) { + generateSpecFromInMemorySchema( + platform, + readAndParseSchema(schemaPath), + outputDirectory, + libraryName, + packageName, + libraryType, + ); +} + module.exports = { execute: generateSpec, + generateSpecFromInMemorySchema: generateSpecFromInMemorySchema, }; diff --git a/packages/react-native/scripts/generate-codegen-artifacts.js b/packages/react-native/scripts/generate-codegen-artifacts.js index bde850b940de2c..00849c8091b8b8 100644 --- a/packages/react-native/scripts/generate-codegen-artifacts.js +++ b/packages/react-native/scripts/generate-codegen-artifacts.js @@ -15,58 +15,13 @@ const yargs = require('yargs'); const argv = yargs .option('p', { alias: 'path', - description: 'Path to React Native application', + description: 'Path to the React Native project root.', }) .option('o', { alias: 'outputPath', - description: 'Path where generated artifacts will be output to', - }) - .option('f', { - alias: 'configFilename', - default: 'package.json', - description: 'The file that contains the codegen configuration.', - }) - .option('k', { - alias: 'configKey', - default: 'codegenConfig', - description: - 'The key that contains the codegen configuration in the config file.', - }) - .option('e', { - alias: 'fabricEnabled', - default: true, - description: 'A flag to control whether to generate fabric components.', - boolean: 'e', - }) - .option('c', { - alias: 'configFileDir', - default: '', - description: - 'Path where codegen config files are located (e.g. node_modules dir).', - }) - .option('n', { - alias: 'nodeBinary', - default: 'node', - description: 'Path to the node executable.', + description: 'Path where generated artifacts will be output to.', }) .usage('Usage: $0 -p [path to app]') .demandOption(['p']).argv; -const CODEGEN_CONFIG_FILENAME = argv.f; -const CODEGEN_CONFIG_FILE_DIR = argv.c; -const CODEGEN_CONFIG_KEY = argv.k; -const CODEGEN_FABRIC_ENABLED = argv.e; -const NODE = argv.n; - -const appRoot = argv.path; -const outputPath = argv.outputPath; - -executor.execute( - appRoot, - outputPath, - NODE, - CODEGEN_CONFIG_FILENAME, - CODEGEN_CONFIG_KEY, - CODEGEN_CONFIG_FILE_DIR, - CODEGEN_FABRIC_ENABLED, -); +executor.execute(argv.path, argv.outputPath); diff --git a/packages/react-native/scripts/generate-provider-cli.js b/packages/react-native/scripts/generate-provider-cli.js index 852a8d300093ac..22afb409405dbd 100644 --- a/packages/react-native/scripts/generate-provider-cli.js +++ b/packages/react-native/scripts/generate-provider-cli.js @@ -9,16 +9,7 @@ 'use strict'; -let RNCodegen; -try { - RNCodegen = require('../packages/react-native-codegen/lib/generators/RNCodegen.js'); -} catch (e) { - RNCodegen = require('@react-native/codegen/lib/generators/RNCodegen.js'); - if (!RNCodegen) { - throw 'RNCodegen not found.'; - } -} - +const utils = require('./codegen/codegen-utils'); const fs = require('fs'); const mkdirp = require('mkdirp'); const yargs = require('yargs'); @@ -81,7 +72,7 @@ function generateProvider(platform, schemaListPath, outputDirectory) { throw new Error(`Invalid platform type. ${platform}`); } - RNCodegen.generateFromSchemas( + utils.getCodegen().generateFromSchemas( { schemas, outputDirectory, diff --git a/packages/react-native/scripts/react_native_pods.rb b/packages/react-native/scripts/react_native_pods.rb index ed040142261bfd..1f6591eb1e361b 100644 --- a/packages/react-native/scripts/react_native_pods.rb +++ b/packages/react-native/scripts/react_native_pods.rb @@ -93,9 +93,10 @@ def use_react_native! ( # Better to rely and enable this environment flag if the new architecture is turned on using flags. relative_path_from_current = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) react_native_version = NewArchitectureHelper.extract_react_native_version(File.join(relative_path_from_current, path)) - ENV['RCT_NEW_ARCH_ENABLED'] = NewArchitectureHelper.compute_new_arch_enabled(new_arch_enabled, react_native_version) - + ENV['USE_NEW_ARCH'] = NewArchitectureHelper.compute_new_arch_enabled(new_arch_enabled, react_native_version) fabric_enabled = fabric_enabled || NewArchitectureHelper.new_arch_enabled + + ENV['RCT_NEW_ARCH_ENABLED'] = "1" ENV['RCT_FABRIC_ENABLED'] = fabric_enabled ? "1" : "0" ENV['USE_HERMES'] = hermes_enabled ? "1" : "0" @@ -103,9 +104,10 @@ def use_react_native! ( ReactNativePodsUtils.warn_if_not_on_arm64() + build_codegen!(prefix, relative_path_from_current) + # The Pods which should be included in all projects pod 'FBLazyVector', :path => "#{prefix}/Libraries/FBLazyVector" - pod 'FBReactNativeSpec', :path => "#{prefix}/React/FBReactNativeSpec" if !NewArchitectureHelper.new_arch_enabled pod 'RCTRequired', :path => "#{prefix}/Libraries/Required" pod 'RCTTypeSafety', :path => "#{prefix}/Libraries/TypeSafety", :modular_headers => true pod 'React', :path => "#{prefix}/" @@ -128,7 +130,8 @@ def use_react_native! ( pod 'React-utils', :path => "#{prefix}/ReactCommon/react/utils" pod 'React-Mapbuffer', :path => "#{prefix}/ReactCommon" pod 'React-jserrorhandler', :path => "#{prefix}/ReactCommon/jserrorhandler" - pod "React-nativeconfig", :path => "#{prefix}/ReactCommon" + pod 'React-nativeconfig', :path => "#{prefix}/ReactCommon" + pod 'RCTDeprecation', :path => "#{prefix}/ReactApple/Libraries/RCTFoundation/RCTDeprecation" if hermes_enabled setup_hermes!(:react_native_path => prefix) @@ -174,16 +177,7 @@ def use_react_native! ( # If the New Arch is turned off, we will use the Old Renderer, though. # RNTester always installed Fabric, this change is required to make the template work. setup_fabric!(:react_native_path => prefix) - checkAndGenerateEmptyThirdPartyProvider!(prefix, NewArchitectureHelper.new_arch_enabled) - - if !fabric_enabled - relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) - build_codegen!(prefix, relative_installation_root) - end - - if NewArchitectureHelper.new_arch_enabled - setup_bridgeless!(:react_native_path => prefix, :use_hermes => hermes_enabled) - end + setup_bridgeless!(:react_native_path => prefix, :use_hermes => hermes_enabled) pods_to_update = LocalPodspecPatch.pods_to_update(:react_native_path => prefix) if !pods_to_update.empty? @@ -282,10 +276,11 @@ def react_native_post_install( ReactNativePodsUtils.update_search_paths(installer) ReactNativePodsUtils.set_use_hermes_build_setting(installer, hermes_enabled) ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path) - ReactNativePodsUtils.apply_flags_for_fabric(installer, fabric_enabled: fabric_enabled) ReactNativePodsUtils.apply_xcode_15_patch(installer) ReactNativePodsUtils.apply_ats_config(installer) ReactNativePodsUtils.updateOSDeploymentTarget(installer) + ReactNativePodsUtils.set_dynamic_frameworks_flags(installer) + ReactNativePodsUtils.add_ndebug_flag_to_pods_in_release(installer) NewArchitectureHelper.set_clang_cxx_language_standard_if_needed(installer) NewArchitectureHelper.modify_flags_for_new_architecture(installer, NewArchitectureHelper.new_arch_enabled) @@ -293,104 +288,3 @@ def react_native_post_install( Pod::UI.puts "Pod install took #{Time.now.to_i - $START_TIME} [s] to run".green end - -# === LEGACY METHOD === -# We need to keep this while we continue to support the old architecture. -# ===================== -def use_react_native_codegen!(spec, options={}) - return if NewArchitectureHelper.new_arch_enabled - # TODO: Once the new codegen approach is ready for use, we should output a warning here to let folks know to migrate. - - # The prefix to react-native - react_native_path = options[:react_native_path] ||= ".." - - # Library name (e.g. FBReactNativeSpec) - library_name = options[:library_name] ||= "#{spec.name.gsub('_','-').split('-').collect(&:capitalize).join}Spec" - Pod::UI.puts "[Codegen] Found #{library_name}" - - relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) - output_dir = options[:output_dir] ||= $CODEGEN_OUTPUT_DIR - output_dir_module = "#{output_dir}/#{$CODEGEN_MODULE_DIR}" - output_dir_component = "#{output_dir}/#{$CODEGEN_COMPONENT_DIR}" - - codegen_config = { - "modules" => { - :js_srcs_pattern => "Native*.js", - :generated_dir => "#{relative_installation_root}/#{output_dir_module}/#{library_name}", - :generated_files => [ - "#{library_name}.h", - "#{library_name}-generated.mm" - ] - }, - "components" => { - :js_srcs_pattern => "*NativeComponent.js", - :generated_dir => "#{relative_installation_root}/#{output_dir_component}/#{library_name}", - :generated_files => [ - "ComponentDescriptors.h", - "EventEmitters.cpp", - "EventEmitters.h", - "Props.cpp", - "Props.h", - "States.cpp", - "States.h", - "RCTComponentViewHelpers.h", - "ShadowNodes.cpp", - "ShadowNodes.h" - ] - } - } - - # The path to JavaScript files - js_srcs_dir = options[:js_srcs_dir] ||= "./" - library_type = options[:library_type] - - if library_type - if !codegen_config[library_type] - raise "[Codegen] invalid library_type: #{library_type}. Check your podspec to make sure it's set to 'modules' or 'components'. Removing the option will generate files for both" - end - js_srcs_pattern = codegen_config[library_type][:js_srcs_pattern] - end - - if library_type - generated_dirs = [ codegen_config[library_type][:generated_dir] ] - generated_files = codegen_config[library_type][:generated_files].map { |filename| "#{codegen_config[library_type][:generated_dir]}/#{filename}" } - else - generated_dirs = [ codegen_config["modules"][:generated_dir], codegen_config["components"][:generated_dir] ] - generated_files = codegen_config["modules"][:generated_files].map { |filename| "#{codegen_config["modules"][:generated_dir]}/#{filename}" } - generated_files = generated_files.concat(codegen_config["components"][:generated_files].map { |filename| "#{codegen_config["components"][:generated_dir]}/#{filename}" }) - end - - if js_srcs_pattern - file_list = `find #{js_srcs_dir} -type f -name #{js_srcs_pattern}`.split("\n").sort - input_files = file_list.map { |filename| "${PODS_TARGET_SRCROOT}/#{filename}" } - else - input_files = [ js_srcs_dir ] - end - - # Prepare filesystem by creating empty files that will be picked up as references by CocoaPods. - prepare_command = "mkdir -p #{generated_dirs.join(" ")} && touch -a #{generated_files.join(" ")}" - system(prepare_command) # Always run prepare_command when a podspec uses the codegen, as CocoaPods may skip invoking this command in certain scenarios. Replace with pre_integrate_hook after updating to CocoaPods 1.11 - spec.prepare_command = prepare_command - - env_files = ["$PODS_ROOT/../.xcode.env.local", "$PODS_ROOT/../.xcode.env"] - - spec.script_phase = { - :name => 'Generate Specs', - :input_files => input_files + env_files, # This also needs to be relative to Xcode - :output_files => ["${DERIVED_FILE_DIR}/codegen-#{library_name}.log"].concat(generated_files.map { |filename| "${PODS_TARGET_SRCROOT}/#{filename}"} ), - # The final generated files will be created when this script is invoked at Xcode build time. - :script => get_script_phases_no_codegen_discovery( - react_native_path: react_native_path, - codegen_output_dir: output_dir, - codegen_module_dir: output_dir_module, - codegen_component_dir: output_dir_component, - library_name: library_name, - library_type: library_type, - js_srcs_pattern: js_srcs_pattern, - js_srcs_dir: js_srcs_dir, - file_list: file_list - ), - :execution_position => :before_compile, - :show_env_vars_in_log => true - } -end diff --git a/packages/react-native/scripts/react_native_pods_utils/__tests__/script_phases.snap.rb b/packages/react-native/scripts/react_native_pods_utils/__tests__/script_phases.snap.rb index e0eadb876940e7..bc216b1315d90a 100644 --- a/packages/react-native/scripts/react_native_pods_utils/__tests__/script_phases.snap.rb +++ b/packages/react-native/scripts/react_native_pods_utils/__tests__/script_phases.snap.rb @@ -11,9 +11,7 @@ def snap_get_script_phases_with_codegen_discovery_with_config_file_dir() export RCT_SCRIPT_RN_DIR=$RCT_SCRIPT_POD_INSTALLATION_ROOT/../.. export RCT_SCRIPT_APP_PATH=$RCT_SCRIPT_POD_INSTALLATION_ROOT/ - export RCT_SCRIPT_CONFIG_FILE_DIR=$RCT_SCRIPT_POD_INSTALLATION_ROOT/node_modules export RCT_SCRIPT_OUTPUT_DIR=$RCT_SCRIPT_POD_INSTALLATION_ROOT - export RCT_SCRIPT_FABRIC_ENABLED=true export RCT_SCRIPT_TYPE=withCodegenDiscovery SCRIPT_PHASES_SCRIPT="$RCT_SCRIPT_RN_DIR/scripts/react_native_pods_utils/script_phases.sh" @@ -30,9 +28,7 @@ def snap_get_script_phases_with_codegen_discovery_without_config_file_dir() export RCT_SCRIPT_RN_DIR=$RCT_SCRIPT_POD_INSTALLATION_ROOT/../.. export RCT_SCRIPT_APP_PATH=$RCT_SCRIPT_POD_INSTALLATION_ROOT/ - export RCT_SCRIPT_CONFIG_FILE_DIR= export RCT_SCRIPT_OUTPUT_DIR=$RCT_SCRIPT_POD_INSTALLATION_ROOT - export RCT_SCRIPT_FABRIC_ENABLED=true export RCT_SCRIPT_TYPE=withCodegenDiscovery SCRIPT_PHASES_SCRIPT="$RCT_SCRIPT_RN_DIR/scripts/react_native_pods_utils/script_phases.sh" diff --git a/packages/react-native/scripts/react_native_pods_utils/script_phases.rb b/packages/react-native/scripts/react_native_pods_utils/script_phases.rb index eb1accba25a285..f5dd2ed708312f 100644 --- a/packages/react-native/scripts/react_native_pods_utils/script_phases.rb +++ b/packages/react-native/scripts/react_native_pods_utils/script_phases.rb @@ -11,9 +11,7 @@ def get_script_phases_with_codegen_discovery(options) export_vars = { 'RCT_SCRIPT_RN_DIR' => "$RCT_SCRIPT_POD_INSTALLATION_ROOT/#{options[:react_native_path]}", 'RCT_SCRIPT_APP_PATH' => "$RCT_SCRIPT_POD_INSTALLATION_ROOT/#{options[:relative_app_root]}", - 'RCT_SCRIPT_CONFIG_FILE_DIR' => "#{options[:relative_config_file_dir] != '' ? "$RCT_SCRIPT_POD_INSTALLATION_ROOT/#{options[:relative_config_file_dir]}" : ''}", 'RCT_SCRIPT_OUTPUT_DIR' => "$RCT_SCRIPT_POD_INSTALLATION_ROOT", - 'RCT_SCRIPT_FABRIC_ENABLED' => "#{options[:fabric_enabled]}", 'RCT_SCRIPT_TYPE' => "withCodegenDiscovery", } return get_script_template(options[:react_native_path], export_vars) diff --git a/packages/react-native/scripts/react_native_pods_utils/script_phases.sh b/packages/react-native/scripts/react_native_pods_utils/script_phases.sh index 4da11277929abc..847702fdb0dabd 100755 --- a/packages/react-native/scripts/react_native_pods_utils/script_phases.sh +++ b/packages/react-native/scripts/react_native_pods_utils/script_phases.sh @@ -76,7 +76,7 @@ generateCodegenSchemaFromJavaScript () { # shellcheck disable=SC2086 # $JS_SRCS not having double quotations is intentional - "$NODE_BINARY" "$CODEGEN_CLI_PATH/lib/cli/combine/combine-js-to-schema-cli.js" "$GENERATED_SCHEMA_FILE" $JS_SRCS + "$NODE_BINARY" "$CODEGEN_CLI_PATH/lib/cli/combine/combine-js-to-schema-cli.js" --exclude NativeSampleTurboModule "$GENERATED_SCHEMA_FILE" $JS_SRCS } generateCodegenArtifactsFromSchema () { @@ -96,7 +96,7 @@ generateCodegenArtifactsFromSchema () { generateArtifacts () { describe "Generating codegen artifacts" pushd "$RCT_SCRIPT_RN_DIR" >/dev/null || exit 1 - "$NODE_BINARY" "scripts/generate-codegen-artifacts.js" --path "$RCT_SCRIPT_APP_PATH" --outputPath "$TEMP_OUTPUT_DIR" --fabricEnabled "$RCT_SCRIPT_FABRIC_ENABLED" --configFileDir "$RCT_SCRIPT_CONFIG_FILE_DIR" --nodeBinary "$NODE_BINARY" + "$NODE_BINARY" "scripts/generate-codegen-artifacts.js" --path "$RCT_SCRIPT_APP_PATH" --outputPath "$TEMP_OUTPUT_DIR" popd >/dev/null || exit 1 } diff --git a/packages/react-native/template/android/build.gradle b/packages/react-native/template/android/build.gradle index 8012362ce17b77..a61601bb05dbf6 100644 --- a/packages/react-native/template/android/build.gradle +++ b/packages/react-native/template/android/build.gradle @@ -1,5 +1,3 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - buildscript { ext { buildToolsVersion = "34.0.0" @@ -19,3 +17,5 @@ buildscript { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") } } + +apply plugin: "com.facebook.react.rootproject" diff --git a/packages/react-native/template/android/gradle-wrapper.jar b/packages/react-native/template/android/gradle-wrapper.jar new file mode 100644 index 00000000000000..d64cd4917707c1 Binary files /dev/null and b/packages/react-native/template/android/gradle-wrapper.jar differ diff --git a/packages/react-native/template/android/gradle-wrapper.properties b/packages/react-native/template/android/gradle-wrapper.properties new file mode 100644 index 00000000000000..e6aba2515d5428 --- /dev/null +++ b/packages/react-native/template/android/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/packages/react-native/template/ios/HelloWorld/Info.plist b/packages/react-native/template/ios/HelloWorld/Info.plist index c004615da4e278..07b050898d9d30 100644 --- a/packages/react-native/template/ios/HelloWorld/Info.plist +++ b/packages/react-native/template/ios/HelloWorld/Info.plist @@ -38,7 +38,7 @@ LaunchScreen UIRequiredDeviceCapabilities - armv7 + arm64 UISupportedInterfaceOrientations diff --git a/packages/rn-tester/NativeComponentExample/MyNativeView.podspec b/packages/rn-tester/NativeComponentExample/MyNativeView.podspec index 23f1db01e1cc11..2e4eb0613d9f41 100644 --- a/packages/rn-tester/NativeComponentExample/MyNativeView.podspec +++ b/packages/rn-tester/NativeComponentExample/MyNativeView.podspec @@ -30,12 +30,4 @@ Pod::Spec.new do |s| s.requires_arc = true install_modules_dependencies(s) - - # Enable codegen for this library - use_react_native_codegen!(s, { - :library_name => "MyNativeViewSpec", - :react_native_path => "../../react-native", - :js_srcs_dir => "./js", - :library_type => "components" - }) end diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h index a13f8336b5fa9a..ed2e3aaaf91c69 100644 --- a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h @@ -24,35 +24,27 @@ namespace facebook::react { #pragma mark - Structs using ConstantsStruct = - NativeCxxModuleExampleCxxBaseConstantsStruct; + NativeCxxModuleExampleCxxConstantsStruct; template <> struct Bridging - : NativeCxxModuleExampleCxxBaseConstantsStructBridging< - bool, - int32_t, - std::string> {}; + : NativeCxxModuleExampleCxxConstantsStructBridging {}; -using ObjectStruct = NativeCxxModuleExampleCxxBaseObjectStruct< +using ObjectStruct = NativeCxxModuleExampleCxxObjectStruct< int32_t, std::string, std::optional>; template <> struct Bridging - : NativeCxxModuleExampleCxxBaseObjectStructBridging< - int32_t, - std::string, - std::optional> {}; + : NativeCxxModuleExampleCxxObjectStructBridging {}; using ValueStruct = - NativeCxxModuleExampleCxxBaseValueStruct; + NativeCxxModuleExampleCxxValueStruct; template <> -struct Bridging : NativeCxxModuleExampleCxxBaseValueStructBridging< - double, - std::string, - ObjectStruct> {}; +struct Bridging + : NativeCxxModuleExampleCxxValueStructBridging {}; #pragma mark - enums enum CustomEnumInt { A = 23, B = 42 }; diff --git a/packages/rn-tester/NativeModuleExample/ScreenshotManager.podspec b/packages/rn-tester/NativeModuleExample/ScreenshotManager.podspec index 2082df5691ed09..17daaf5934d9fd 100644 --- a/packages/rn-tester/NativeModuleExample/ScreenshotManager.podspec +++ b/packages/rn-tester/NativeModuleExample/ScreenshotManager.podspec @@ -23,13 +23,4 @@ Pod::Spec.new do |s| s.requires_arc = true install_modules_dependencies(s) - - # s.dependency "..." - - # Enable codegen for this library - use_react_native_codegen!(s, { - :react_native_path => "../../react-native", - :js_srcs_dir => "./", - :library_type => "modules", - }) end diff --git a/packages/rn-tester/Podfile b/packages/rn-tester/Podfile index 8991d28a670e07..7a9bda7f3f9ffa 100644 --- a/packages/rn-tester/Podfile +++ b/packages/rn-tester/Podfile @@ -55,16 +55,12 @@ def pods(target_name, options = {}) # Additional Pods which aren't included in the default Podfile pod 'React-RCTPushNotification', :path => "#{@prefix_path}/Libraries/PushNotificationIOS" - pod 'Yoga', :path => "#{@prefix_path}/ReactCommon/yoga", :modular_headers => true # Additional Pods which are classed as unstable # RNTester native modules and components pod 'ScreenshotManager', :path => "NativeModuleExample" - - if ENV['RCT_NEW_ARCH_ENABLED'] == '1' - pod 'MyNativeView', :path => "NativeComponentExample" - pod 'NativeCxxModuleExample', :path => "NativeCxxModuleExample" - end + pod 'MyNativeView', :path => "NativeComponentExample" + pod 'NativeCxxModuleExample', :path => "NativeCxxModuleExample" end target 'RNTester' do diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index 2d38f0181b3f63..c3ac6564e8ec77 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -2,13 +2,6 @@ PODS: - boost (1.83.0) - DoubleConversion (1.1.6) - FBLazyVector (1000.0.0) - - FBReactNativeSpec (1000.0.0): - - RCT-Folly (= 2023.08.07.00) - - RCTRequired (= 1000.0.0) - - RCTTypeSafety (= 1000.0.0) - - React-Core (= 1000.0.0) - - React-jsi (= 1000.0.0) - - ReactCommon/turbomodule/core (= 1000.0.0) - fmt (9.1.0) - glog (0.3.5) - hermes-engine (1000.0.0): @@ -20,6 +13,44 @@ PODS: - hermes-engine/inspector (1000.0.0) - hermes-engine/inspector_chrome (1000.0.0) - hermes-engine/Public (1000.0.0) + - MyNativeView (0.0.1): + - glog + - hermes-engine + - RCT-Folly (= 2023.08.07.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - NativeCxxModuleExample (0.0.1): + - glog + - hermes-engine + - RCT-Folly (= 2023.08.07.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - OCMock (3.9.1) - RCT-Folly (2023.08.07.00): - boost @@ -37,6 +68,7 @@ PODS: - DoubleConversion - fmt (= 9.1.0) - glog + - RCTDeprecation (1000.0.0) - RCTRequired (1000.0.0) - RCTTypeSafety (1000.0.0): - FBLazyVector (= 1000.0.0) @@ -58,7 +90,6 @@ PODS: - React-callinvoker (1000.0.0) - React-Codegen (1000.0.0): - DoubleConversion - - FBReactNativeSpec - glog - hermes-engine - RCT-Folly @@ -72,7 +103,6 @@ PODS: - React-jsiexecutor - React-NativeModulesApple - React-rendererdebug - - React-rncore - React-utils - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core @@ -80,6 +110,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default (= 1000.0.0) - React-cxxreact - React-hermes @@ -94,6 +125,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -108,6 +140,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-cxxreact - React-hermes - React-jsi @@ -121,6 +154,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default (= 1000.0.0) - React-Core/RCTWebSocket (= 1000.0.0) - React-cxxreact @@ -137,6 +171,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -151,6 +186,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -165,6 +201,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -179,6 +216,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -193,6 +231,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -207,6 +246,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -221,6 +261,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -235,6 +276,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -249,6 +291,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -263,6 +306,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default - React-cxxreact - React-hermes @@ -277,6 +321,7 @@ PODS: - glog - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTDeprecation - React-Core/Default (= 1000.0.0) - React-cxxreact - React-hermes @@ -888,6 +933,7 @@ PODS: - DoubleConversion - fmt (= 9.1.0) - glog + - hermes-engine - RCT-Folly (= 2023.08.07.00) - React-jsiexecutor (1000.0.0): - DoubleConversion @@ -1097,8 +1143,23 @@ PODS: - React-perflogger (= 1000.0.0) - ScreenshotManager (0.0.1): - glog + - hermes-engine - RCT-Folly (= 2023.08.07.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen - React-Core + - React-debug + - React-Fabric + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - SocketRocket (0.7.0) - Yoga (0.0.0) @@ -1106,13 +1167,15 @@ DEPENDENCIES: - boost (from `../react-native/third-party-podspecs/boost.podspec`) - DoubleConversion (from `../react-native/third-party-podspecs/DoubleConversion.podspec`) - FBLazyVector (from `../react-native/Libraries/FBLazyVector`) - - FBReactNativeSpec (from `../react-native/React/FBReactNativeSpec`) - fmt (from `../react-native/third-party-podspecs/fmt.podspec`) - glog (from `../react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../react-native/sdks/hermes-engine/hermes-engine.podspec`) + - MyNativeView (from `NativeComponentExample`) + - NativeCxxModuleExample (from `NativeCxxModuleExample`) - OCMock (~> 3.9.1) - RCT-Folly (from `../react-native/third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCTDeprecation (from `../react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) - RCTRequired (from `../react-native/Libraries/Required`) - RCTTypeSafety (from `../react-native/Libraries/TypeSafety`) - React (from `../react-native/`) @@ -1172,8 +1235,6 @@ EXTERNAL SOURCES: :podspec: "../react-native/third-party-podspecs/DoubleConversion.podspec" FBLazyVector: :path: "../react-native/Libraries/FBLazyVector" - FBReactNativeSpec: - :path: "../react-native/React/FBReactNativeSpec" fmt: :podspec: "../react-native/third-party-podspecs/fmt.podspec" glog: @@ -1181,8 +1242,14 @@ EXTERNAL SOURCES: hermes-engine: :podspec: "../react-native/sdks/hermes-engine/hermes-engine.podspec" :tag: '' + MyNativeView: + :path: NativeComponentExample + NativeCxxModuleExample: + :path: NativeCxxModuleExample RCT-Folly: :podspec: "../react-native/third-party-podspecs/RCT-Folly.podspec" + RCTDeprecation: + :path: "../react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation" RCTRequired: :path: "../react-native/Libraries/Required" RCTTypeSafety: @@ -1278,18 +1345,20 @@ SPEC CHECKSUMS: boost: 26fad476bfa736552bbfa698a06cc530475c1505 DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953 FBLazyVector: f4492a543c5a8fa1502d3a5867e3f7252497cfe8 - FBReactNativeSpec: 03da6018f583d64c5944bc4afffb12368e3642a8 fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120 glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 - hermes-engine: 2788dfc2ed3699d11b14e815f0c608fc8d770d6b + hermes-engine: 3cf266f7eba66a16bcc83d939def2899e6d1a717 + MyNativeView: 1fb0d21fda6ef12fd5f425f9888c81345a86a3e7 + NativeCxxModuleExample: 19d10636011c914264a5922c6f0f22a2e8fd0910 OCMock: 9491e4bec59e0b267d52a9184ff5605995e74be8 RCT-Folly: 823c6f6ec910a75d4ad28898b4a11cdee140b92a + RCTDeprecation: 3808e36294137f9ee5668f4df2e73dc079cd1dcf RCTRequired: 82c56a03b3efd524bfdb581a906add903f78f978 RCTTypeSafety: 5f57d4ae5dfafc85a0f575d756c909b584722c52 React: cb6dc75e09f32aeddb4d8fb58a394a67219a92fe React-callinvoker: bae59cbd6affd712bbfc703839dad868ff35069d - React-Codegen: 20baee7c8f2303bc5f34d9e72f93ca55de6cbde3 - React-Core: f09ea29184cc7f33015a0748588fcfe1d43b3dd1 + React-Codegen: c1e6ea0005a6ecf187d2772f14e5386f1c1f4853 + React-Core: aaf2be188dfb2c342bc504042a92bfff31e2048f React-CoreModules: ad1b7cb8efe5f3c7e88548b6ea6aad8507774471 React-cxxreact: 04bf6a12caa850f5d2c7bd6d66dfecd4741989b5 React-debug: 296b501a90c41f83961f58c6d96a01330d499da5 @@ -1299,7 +1368,7 @@ SPEC CHECKSUMS: React-hermes: f192759ffeb9714917e9c39850ac349d8ea982d8 React-ImageManager: 691c4a56320ab9ab10482cd6306b3a4da004b79c React-jserrorhandler: 79fb3a8860fb1ea22dc77765aac15775593d4f8f - React-jsi: 3c1d8048abf3eaca913944bd9835333bb7b415d4 + React-jsi: 81f4e5b414c992c16c02e22e975a45aeb2b166e4 React-jsiexecutor: 1212e26a01ce4de7443123f0ce090ec1affb3220 React-jsinspector: c867db3338992200616103b2f0ca6882c0c0482d React-logger: 8486d7a1d32b972414b1d34a93470ee2562c6ee2 @@ -1321,16 +1390,16 @@ SPEC CHECKSUMS: React-RCTText: d9925903524a7b179cf7803162a98038e0bfb4fd React-RCTVibration: 14322c13fb0c5cc2884b714b11d277dc7fc326c4 React-rendererdebug: 2e58409db231638bc3e78143d8844066a3302939 - React-rncore: 63aced0ca8aff46f8e762663ca4afebb5eedb627 + React-rncore: e903b3d2819a25674403c548ec103f34bf02ba2b React-runtimeexecutor: e1c32bc249dd3cf3919cb4664fd8dc84ef70cff7 React-runtimescheduler: 6529d155a98010b6e8f0a3a86d4184b89a886633 React-utils: 87ed8c079c9991831112fe716f2686c430699fc3 ReactCommon: 4511ea0e8f349de031de7cad88c2ecf871ab69f9 ReactCommon-Samples: cfc3383af93a741319e038977c2ae1082e4ff49e - ScreenshotManager: 2b23b74d25f5e307f7b4d21173a61a3934e69475 + ScreenshotManager: 753da20873c2ada484bdee4143a7248084d3fd35 SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d - Yoga: 455fa6867657b570a05655dd515c8c6588618fa8 + Yoga: dcc90b6f6863e467adabdd4f4bd963da1faddf1d -PODFILE CHECKSUM: c0120ff99aea9c7141bc22179e0f6be99c81a601 +PODFILE CHECKSUM: 426f495a1ad44f3cabea3b7dd2b66a0b71083e26 COCOAPODS: 1.13.0 diff --git a/packages/rn-tester/RNTester/AppDelegate.mm b/packages/rn-tester/RNTester/AppDelegate.mm index 16a33fa3cab524..0692f5b4cb5eea 100644 --- a/packages/rn-tester/RNTester/AppDelegate.mm +++ b/packages/rn-tester/RNTester/AppDelegate.mm @@ -16,11 +16,14 @@ #import #endif -#if RCT_NEW_ARCH_ENABLED #import #ifndef RN_DISABLE_OSS_PLUGIN_HEADER #import #endif + +// FB-internal imports +#ifdef RN_DISABLE_OSS_PLUGIN_HEADER +#import #endif #if BUNDLE_PATH @@ -33,6 +36,11 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { +#ifdef RN_DISABLE_OSS_PLUGIN_HEADER + // FB-internal app init setup. + RCTFBAppInitApplicationDidFinishLaunching(launchOptions); +#endif + self.moduleName = @"RNTesterApp"; // You can add your custom initial props in the dictionary below. // They will be passed down to the ViewController used by React Native. @@ -78,11 +86,9 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge if (name == std::string([@"SampleTurboCxxModule" UTF8String])) { return std::make_shared(jsInvoker); } -#ifdef RCT_NEW_ARCH_ENABLED if (name == facebook::react::NativeCxxModuleExample::kModuleName) { return std::make_shared(jsInvoker); } -#endif return nullptr; } @@ -119,7 +125,6 @@ - (void)application:(__unused UIApplication *)application #pragma mark - RCTComponentViewFactoryComponentProvider -#if RCT_NEW_ARCH_ENABLED #ifndef RN_DISABLE_OSS_PLUGIN_HEADER - (nonnull NSDictionary> *)thirdPartyFabricComponents { @@ -131,6 +136,5 @@ - (NSURL *)bundleURL { return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:kBundlePath]; } -#endif @end diff --git a/packages/rn-tester/RNTester/Info.plist b/packages/rn-tester/RNTester/Info.plist index 8e05c22beec181..50c8a4c0f3ddb0 100644 --- a/packages/rn-tester/RNTester/Info.plist +++ b/packages/rn-tester/RNTester/Info.plist @@ -50,7 +50,7 @@ LaunchScreen UIRequiredDeviceCapabilities - armv7 + arm64 UISupportedInterfaceOrientations diff --git a/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj b/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj index ff0cf5e629d1e3..848876452f472a 100644 --- a/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj +++ b/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj @@ -933,10 +933,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 13.4; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = ( - "$(inherited)", - "-DRN_FABRIC_ENABLED", - ); + OTHER_CFLAGS = "$(inherited)"; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", @@ -944,7 +941,6 @@ "-DFOLLY_USE_LIBCPP=1", "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", - "-DRN_FABRIC_ENABLED", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1029,10 +1025,7 @@ ); IPHONEOS_DEPLOYMENT_TARGET = 13.4; MTL_ENABLE_DEBUG_INFO = NO; - OTHER_CFLAGS = ( - "$(inherited)", - "-DRN_FABRIC_ENABLED", - ); + OTHER_CFLAGS = "$(inherited)"; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", @@ -1040,7 +1033,6 @@ "-DFOLLY_USE_LIBCPP=1", "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", - "-DRN_FABRIC_ENABLED", ); OTHER_LDFLAGS = ( "-ObjC", diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterActivity.kt b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterActivity.kt index e2e13d7dc96f0f..ad9bff582193b4 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterActivity.kt +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterActivity.kt @@ -20,12 +20,11 @@ class RNTesterActivity : ReactActivity() { override fun onCreate(savedInstanceState: Bundle?) { // Get remote param before calling super which uses it - val bundle = activity.getIntent()?.getExtras() + val bundle = activity.intent?.extras if (bundle != null && bundle.containsKey(PARAM_ROUTE)) { val routeUri = "rntester://example/${bundle.getString(PARAM_ROUTE)}Example" - initialProps = Bundle() - initialProps?.putString("exampleFromAppetizeParams", routeUri) + initialProps = Bundle().apply { putString("exampleFromAppetizeParams", routeUri) } } super.onCreate(savedInstanceState) diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyLegacyViewManager.kt b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyLegacyViewManager.kt index d7e101b7d3c5dc..11df7bb0f60f31 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyLegacyViewManager.kt +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyLegacyViewManager.kt @@ -35,15 +35,15 @@ internal class MyLegacyViewManager(reactContext: ReactApplicationContext) : } @ReactProp(name = ViewProps.COLOR) - fun setColor(view: MyNativeView, color: String) { - view.setBackgroundColor(Color.parseColor(color)) - } + fun setColor(view: MyNativeView, color: String?): Unit = + when (color) { + null -> view.setBackgroundColor(Color.TRANSPARENT) + else -> view.setBackgroundColor(Color.parseColor(color)) + } @ReactProp(name = "cornerRadius") fun setCornerRadius(view: MyNativeView, cornerRadius: Float) { - if (cornerRadius !== null) { - view.setCornerRadius(cornerRadius) - } + view.setCornerRadius(cornerRadius) } override fun getExportedViewConstants(): Map = mapOf("PI" to 3.14) diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeView.kt b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeView.kt index c9365d728025c7..50e7708a422650 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeView.kt +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeView.kt @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +@file:Suppress("DEPRECATION") // As we want to test RCTEventEmitter here package com.facebook.react.uiapp.component import android.graphics.Color diff --git a/packages/rn-tester/js/RNTesterAppShared.js b/packages/rn-tester/js/RNTesterAppShared.js index 04c17f58f32596..27260cc901a120 100644 --- a/packages/rn-tester/js/RNTesterAppShared.js +++ b/packages/rn-tester/js/RNTesterAppShared.js @@ -8,6 +8,8 @@ * @flow */ +import type {RNTesterModuleInfo} from './types/RNTesterTypes'; + import RNTesterModuleContainer from './components/RNTesterModuleContainer'; import RNTesterModuleList from './components/RNTesterModuleList'; import RNTesterNavBar, {navBarHeight} from './components/RNTesterNavbar'; @@ -24,11 +26,24 @@ import { initialNavigationState, } from './utils/testerStateUtils'; import * as React from 'react'; -import {BackHandler, StyleSheet, View, useColorScheme} from 'react-native'; +import { + BackHandler, + Linking, + StyleSheet, + View, + useColorScheme, +} from 'react-native'; // RNTester App currently uses in memory storage for storing navigation state -const RNTesterApp = (): React.Node => { +const RNTesterApp = ({ + testList, +}: { + testList?: { + components?: Array, + apis?: Array, + }, +}): React.Node => { const [state, dispatch] = React.useReducer( RNTesterNavigationReducer, initialNavigationState, @@ -44,8 +59,8 @@ const RNTesterApp = (): React.Node => { } = state; const examplesList = React.useMemo( - () => getExamplesListWithRecentlyUsed({recentlyUsed}), - [recentlyUsed], + () => getExamplesListWithRecentlyUsed({recentlyUsed, testList}), + [recentlyUsed, testList], ); const handleBackPress = React.useCallback(() => { @@ -104,6 +119,45 @@ const RNTesterApp = (): React.Node => { [dispatch], ); + // Setup Linking event subscription + const handleOpenUrlRequest = React.useCallback( + ({url}: {url: string, ...}) => { + // Supported URL pattern(s): + // * rntester://example/ + const match = /^rntester:\/\/example\/(.+)$/.exec(url); + if (!match) { + console.warn( + `handleOpenUrlRequest: Received unsupported URL: '${url}'`, + ); + return; + } + + const key = match[1]; + const exampleModule = RNTesterList.Modules[key]; + if (exampleModule == null) { + console.warn( + `handleOpenUrlRequest: Unable to find requested module with key: '${key}'`, + ); + return; + } + + console.log(`handleOpenUrlRequest: Opening example '${key}'`); + + dispatch({ + type: RNTesterNavigationActionsType.EXAMPLE_OPEN_URL_REQUEST, + data: { + key, + title: exampleModule.title || key, + }, + }); + }, + [dispatch], + ); + React.useEffect(() => { + const subscription = Linking.addEventListener('url', handleOpenUrlRequest); + return () => subscription.remove(); + }, [handleOpenUrlRequest]); + const theme = colorScheme === 'dark' ? themes.dark : themes.light; if (examplesList === null) { diff --git a/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js b/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js index d0ad866155858d..35347b720cedc6 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js @@ -196,10 +196,20 @@ const examples: Array = [ + + ); }, @@ -470,7 +480,7 @@ const examples: Array = [ 'next', ]; const returnKeyLabels = ['Compile', 'React Native']; - const examples = returnKeyTypes.map(type => { + const returnKeyExamples = returnKeyTypes.map(type => { return ( = [ }); return ( - {examples} + {returnKeyExamples} {types} ); diff --git a/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js b/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js index f4135cc5b5ffc3..189c3a5fd21475 100644 --- a/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js +++ b/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js @@ -55,7 +55,9 @@ type Examples = | 'rejectPromise' | 'voidFunc' | 'optionalArgs' - | 'emitDeviceEvent' + | 'emitDeviceEvent'; + +type ErrorExamples = | 'voidFuncThrows' | 'getObjectThrows' | 'promiseThrows' @@ -131,6 +133,10 @@ class NativeCxxModuleExampleExample extends React.Component<{||}, State> { }); NativeCxxModuleExample?.emitCustomDeviceEvent(CUSTOM_EVENT_TYPE); }, + }; + + // $FlowFixMe[missing-local-annot] + _errorTests = { voidFuncThrows: () => { try { NativeCxxModuleExample?.voidFuncThrows(); @@ -202,7 +208,7 @@ class NativeCxxModuleExampleExample extends React.Component<{||}, State> { })); } - _renderResult(name: Examples): React.Node { + _renderResult(name: Examples | ErrorExamples): React.Node { const result = this.state.testResults[name] || {}; return ( @@ -231,7 +237,7 @@ class NativeCxxModuleExampleExample extends React.Component<{||}, State> { this._setResult(item, this._tests[item]()), ) }> - Run all tests + Run function call tests this.setState({testResults: {}})} @@ -254,6 +260,24 @@ class NativeCxxModuleExampleExample extends React.Component<{||}, State> { )} /> + + Report errors tests + + item} + renderItem={({item}: {item: ErrorExamples, ...}) => ( + + this._setResult(item, this._errorTests[item]())}> + {item} + + {this._renderResult(item)} + + )} + /> ); } diff --git a/packages/rn-tester/js/utils/RNTesterNavigationReducer.js b/packages/rn-tester/js/utils/RNTesterNavigationReducer.js index 9c2097d668cadc..db59ba5a7a75de 100644 --- a/packages/rn-tester/js/utils/RNTesterNavigationReducer.js +++ b/packages/rn-tester/js/utils/RNTesterNavigationReducer.js @@ -18,6 +18,7 @@ export const RNTesterNavigationActionsType = { BACK_BUTTON_PRESS: 'BACK_BUTTON_PRESS', MODULE_CARD_PRESS: 'MODULE_CARD_PRESS', EXAMPLE_CARD_PRESS: 'EXAMPLE_CARD_PRESS', + EXAMPLE_OPEN_URL_REQUEST: 'EXAMPLE_OPEN_URL_REQUEST', }; const getUpdatedRecentlyUsed = ({ @@ -100,6 +101,14 @@ export const RNTesterNavigationReducer = ( state.activeModuleExampleKey != null ? state.activeModuleTitle : null, }; + case RNTesterNavigationActionsType.EXAMPLE_OPEN_URL_REQUEST: + return { + ...state, + activeModuleKey: key, + activeModuleTitle: title, + activeModuleExampleKey: null, + }; + default: throw new Error(`Invalid action type ${action.type}`); } diff --git a/packages/rn-tester/js/utils/testerStateUtils.js b/packages/rn-tester/js/utils/testerStateUtils.js index c3239adeab9737..805cfe83349e8c 100644 --- a/packages/rn-tester/js/utils/testerStateUtils.js +++ b/packages/rn-tester/js/utils/testerStateUtils.js @@ -48,15 +48,21 @@ const filterEmptySections = (examplesList: ExamplesList): any => { export const getExamplesListWithRecentlyUsed = ({ recentlyUsed, + testList, }: { recentlyUsed: ComponentList, + testList?: { + components?: Array, + apis?: Array, + }, }): ExamplesList | null => { // Return early if state has not been initialized from storage if (!recentlyUsed) { return null; } - const components = RNTesterList.Components.map( + const componentList = testList?.components ?? RNTesterList.Components; + const components = componentList.map( (componentExample): RNTesterModuleInfo => ({ ...componentExample, exampleType: Screens.COMPONENTS, @@ -69,7 +75,8 @@ export const getExamplesListWithRecentlyUsed = ({ ) .filter(Boolean); - const apis = RNTesterList.APIs.map((apiExample): RNTesterModuleInfo => ({ + const apisList = testList?.apis ?? RNTesterList.APIs; + const apis = apisList.map((apiExample): RNTesterModuleInfo => ({ ...apiExample, exampleType: Screens.APIS, })); diff --git a/scripts/test-e2e-local.js b/scripts/test-e2e-local.js index 410cb199283cd2..353490696d47cf 100644 --- a/scripts/test-e2e-local.js +++ b/scripts/test-e2e-local.js @@ -37,8 +37,9 @@ const argv = yargs }) .option('p', { alias: 'platform', - default: 'iOS', - choices: ['iOS', 'Android'], + default: 'ios', + coerce: platform => platform.toLowerCase(), + choices: ['ios', 'android'], }) .option('h', { alias: 'hermes', @@ -167,7 +168,7 @@ async function testRNTester(circleCIArtifacts, onReleaseBranch) { // see also https://github.com/shelljs/shelljs/issues/86 pushd('packages/rn-tester'); - if (argv.platform === 'iOS') { + if (argv.platform === 'ios') { await testRNTesterIOS(circleCIArtifacts, onReleaseBranch); } else { await testRNTesterAndroid(circleCIArtifacts); @@ -248,7 +249,7 @@ async function testRNTestProject(circleCIArtifacts) { ); } - if (argv.platform === 'iOS') { + if (argv.platform === 'ios') { // doing the pod install here so that it's easier to play around RNTestProject cd('ios'); exec('bundle install'); diff --git a/yarn.lock b/yarn.lock index 14c94894550844..d90db7f0cd2126 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5143,23 +5143,23 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== -flow-api-translator@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/flow-api-translator/-/flow-api-translator-0.17.1.tgz#fee650b8c975338aea46be9e40464bcab81fbedf" - integrity sha512-TzOWylttBRQ8zco5Nmu7+11c45WpLgO1BPXe9R0nCoUo6x2IU4baC1AjnQEistsrMkG+Imlp2q3TFk6pRcJp0w== +flow-api-translator@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/flow-api-translator/-/flow-api-translator-0.18.0.tgz#c8fe149c3211638bba565d4ebbde10f05424acc2" + integrity sha512-X6LMMTGsYtJWJmaye0W10UOFQoxVQxm5nJkUDcX6nT3O0KpsV/5SNo7uf4KWzNGnb4u60p1IKx7ghBRJbUqV1w== dependencies: "@babel/code-frame" "^7.16.0" "@typescript-eslint/visitor-keys" "^5.42.0" flow-enums-runtime "^0.0.6" - hermes-eslint "0.17.1" - hermes-estree "0.17.1" - hermes-parser "0.17.1" - hermes-transform "0.17.1" + hermes-eslint "0.18.0" + hermes-estree "0.18.0" + hermes-parser "0.18.0" + hermes-transform "0.18.0" -flow-bin@^0.222.0: - version "0.222.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.222.0.tgz#b4ca588c77fbd79db1edf38615cd04d114c1e933" - integrity sha512-U2047+pOX1EutHGykcjtamAlP8UIHrxbkexB5zPVQ8PH+WcVmD4PtRE6J8Jc3S6odyo0AqVnQsI4rE/2x2fGmQ== +flow-bin@^0.223.0: + version "0.223.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.223.0.tgz#38fb6efd6c202b774d01834ded0620eb8eebad89" + integrity sha512-E+GmTcBTPIRfnX/Dk19zJewX9grxoVQU+RG3Ypd/Os0OkUSOF7K3Sxo2I+8Oz1EpnPMGhnbM4WRAUuY0JaHRsw== flow-enums-runtime@^0.0.6: version "0.0.6" @@ -5543,24 +5543,24 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hermes-eslint@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/hermes-eslint/-/hermes-eslint-0.17.1.tgz#e5e43091082dc53a060e0b002324e68943104b71" - integrity sha512-g3z4L84pHKrBMRtbfifalpbNbNear0cEygAe+geCmCj1GUrqQu+RDeBZOYERHv0HOq0aDxjTZhj3m4fD/YVUwg== +hermes-eslint@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/hermes-eslint/-/hermes-eslint-0.18.0.tgz#16e7d5c7742f709d814d6a5a5d955803e81b328d" + integrity sha512-NIh8Utqk32+voL1b4ngCRnMQ0XCRzFbon7IG25lhnSYCTezX5besIK+79pUHw1YEDZVGrVrMxeIYxXiamLzcUQ== dependencies: esrecurse "^4.3.0" - hermes-estree "0.17.1" - hermes-parser "0.17.1" + hermes-estree "0.18.0" + hermes-parser "0.18.0" hermes-estree@0.17.0: version "0.17.0" resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.17.0.tgz#4b1b0d8131826178f0af79a317ceaca3723e9012" integrity sha512-bW9+bMZqnro+0+l6dUqTJW0VaNUvs4HRHh/J7VotTGnMmhBFRIcJz6ZxrRE7xIXmK7S5bJE9qrEooSiig4N70g== -hermes-estree@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.17.1.tgz#902806a900c185720424ffcf958027821d23c051" - integrity sha512-EdUJms+eRE40OQxysFlPr1mPpvUbbMi7uDAKlScBw8o3tQY22BZ5yx56OYyp1bVaBm+7Cjc3NQz24sJEFXkPxg== +hermes-estree@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.18.0.tgz#6c202d8c78ddefadf3eb595a584dfa55b51a0508" + integrity sha512-WaIudIVKo5QWFqz1ta53HqSDuVxYST/MUuP9X7dqUpbHse3E2gzJq/7hEtgx84hh2XSNWN1AhYho3ThOA85uCA== hermes-parser@0.17.0: version "0.17.0" @@ -5569,12 +5569,12 @@ hermes-parser@0.17.0: dependencies: hermes-estree "0.17.0" -hermes-parser@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.17.1.tgz#8b5cbaff235fed28487812ad718f9c7182d0db0f" - integrity sha512-yErtFLMEL6490fFJPurNn23OI2ciGAtaUfKUg9VPdcde9CmItCjOVQkJt1Xzawv5kuRzeIx0RE2E2Q9TbIgdzA== +hermes-parser@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.18.0.tgz#dd9878f70e9ca2570e7626181ae0465115f7f78d" + integrity sha512-DIIM6vsy30BU5hNkOXh6MR2r4ZAxVhbfyTnmfo/rqUf3KySlNWn9fWiOcpuGAdDN2o5sdPCpu6cep3a23d1Klw== dependencies: - hermes-estree "0.17.1" + hermes-estree "0.18.0" hermes-profile-transformer@^0.0.6: version "0.0.6" @@ -5583,17 +5583,17 @@ hermes-profile-transformer@^0.0.6: dependencies: source-map "^0.7.3" -hermes-transform@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/hermes-transform/-/hermes-transform-0.17.1.tgz#8dc60f4744137b936c15aac9231a951268450600" - integrity sha512-0QlknKahueDHeswUjruzyvdfqtaw4OC4JuWYNWqAr8HP+1YGx3J2lwsGuQeaJhkC04eh9lhO9cc5/xfJLBr74A== +hermes-transform@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/hermes-transform/-/hermes-transform-0.18.0.tgz#e5718960ddf5c2c938397523085c0ac58159cc20" + integrity sha512-jbzeRDseWlUNhErS0ovt6/IpNcSEtYEytg6LTFox+4qDbrX5Tg6AO5xdNwMLgxPxD/03xAicBZL44/yI+4YXgA== dependencies: "@babel/code-frame" "^7.16.0" esquery "^1.4.0" flow-enums-runtime "^0.0.6" - hermes-eslint "0.17.1" - hermes-estree "0.17.1" - hermes-parser "0.17.1" + hermes-eslint "0.18.0" + hermes-estree "0.18.0" + hermes-parser "0.18.0" homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.3" @@ -7877,14 +7877,14 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier-plugin-hermes-parser@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/prettier-plugin-hermes-parser/-/prettier-plugin-hermes-parser-0.17.1.tgz#f7c461fe875f7a365442fc69a51434b7e3ff88e4" - integrity sha512-ULX366DyQrrFW//a6Zgj0r/CF4a4Ijg+TCaplOtYCPCu4qThUp9XrMRSYWeB0lacD1lmWFqRDFL5R8Oxmhpw3A== +prettier-plugin-hermes-parser@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/prettier-plugin-hermes-parser/-/prettier-plugin-hermes-parser-0.18.0.tgz#00b6d979f8068c4fab72500c1abb5a8dcc107645" + integrity sha512-gU/K9jjJYDzdn1PLJdjhaHk+27POGrSbxVxBUOVm9qOiIpnwW1IeYA3sHg2PpCJLUQyJM7R6jiesQgPgvUHkmA== dependencies: - hermes-estree "0.17.1" - hermes-parser "0.17.1" - prettier-plugin-hermes-parser "0.17.1" + hermes-estree "0.18.0" + hermes-parser "0.18.0" + prettier-plugin-hermes-parser "0.18.0" prettier@2.8.8: version "2.8.8"