Compare commits

..
Author SHA1 Message Date
CodemodService Bot d90b163998 Fix CQS signal modernize-use-using in xplat/js/react-native-github/packages [A] [B] [A]
Reviewed By: dtolnay

Differential Revision: D78562730
2025-07-18 19:18:43 -07:00
Sam Zhou 1ceba3b470 Prepare react-native for prettier v3 (#52717)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52717

Prettier v3 no longer loads plugin implicitly. This diff first configures the hermes-parser plugin explicitly to prepare for v3 rollout.

Changelog: [Internal]

Reviewed By: pieterv

Differential Revision: D78590158

fbshipit-source-id: dba06f5a823488b72a30ae5b58e37e172f4e736f
2025-07-18 17:51:14 -07:00
Nick Gerleman b3d1d2a0a5 Disable Measure Cache When Also Using Prepared Text Layout (#52714)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52714

If we also have prepared text layout enabled, this cache will fill up with the last 1000 TextInput AttributedString, which isn't very useful. Let's assume we want to get rid of this cache, when we have the prepared layout cache as well.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D78534088

fbshipit-source-id: e9020ebfb7e1210f19e0b31f7423e7a9a90a89d1
2025-07-18 15:19:58 -07:00
Nick Gerleman ea394f6229 Fix incorrect hit testing on text when layout reused (#52692)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52692

D77341994 added a global cache for Facsimile layouts, where we will reuse an existing `android.text.Layout`, and `Spannable`, if one already existed for a same AttributedString, under same layout constraints. An error here, is that we consider a layout reusable, even when shadow views are different, which means there may be different react tags in the underlying AttributedString.

This leaks into the layout itself, and means that if a layout is reused, we can hit test against a stale/incorrect react tag.

The solution to allow reuse here, is to avoid embedding react tag directly into the `android.text.Layout` structure. Instead, we replace references to react tags, with a fragment index, and embed the list of fragment indices in each PreparedLayout. We can hide this "cleverness" within the boundary of `TextLayoutManager`, such that an invalid `PreparedLayout` is never allowed to escape.

Changelog: [Internal]

Reviewed By: joevilches

Differential Revision: D78516079

fbshipit-source-id: 2d9fe9d80f60e6d7e7e40080a0817a08b51c3153
2025-07-18 15:19:58 -07:00
Luna Wei 7ea0ef7a90 Implement windowFocus on ReactVirtualViewExperiment (#52690)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52690

Changelog: [Internal] - Add the window focus experiment to ReactVirtualViewExperimental

Reviewed By: yungsters

Differential Revision: D78502991

fbshipit-source-id: 3e72561835925040e5b240e71734a088908957ed
2025-07-18 14:16:22 -07:00
Luna Wei 36fed563c4 Use experimental VirtualView in FlatListVirtualColumn (#52689)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52689

Changelog: [Internal] - Add support for experimental VirtualView in polyfill

Reviewed By: mdvacca

Differential Revision: D78450011

fbshipit-source-id: cc30394eb1a008cc8c023db2aaf0a6a6ffcd16df
2025-07-18 14:16:22 -07:00
Nicola Corti 391a6b87a0 Rollout preventShadowTreeCommitExhaustionWithLocking in experimental (#52709)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52709

We want to make user for folks in OSS to try
`preventShadowTreeCommitExhaustionWithLocking`. Therefore I'm updating the OSS
release channel for this flag to experimental.

Changelog:
[Internal] [Changed] - Rollout `preventShadowTreeCommitExhaustionWithLocking` in experimental

Reviewed By: rubennorte

Differential Revision: D78558655

fbshipit-source-id: 02a9d216c7b2f8f7bdc1340213f82b70c5692dc7
2025-07-18 10:20:19 -07:00
generatedunixname89002005287564 81c2e798d7 Fix CQS signal readability-braces-around-statements in xplat/js/react-native-github/packages (#52700)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52700

Pull Request resolved: https://github.com/facebook/react-native/pull/52699

Reviewed By: cipolleschi

Differential Revision: D78549834

fbshipit-source-id: a15a9faed579a1e650eabb6e028a48f9307ad22b
2025-07-18 09:30:15 -07:00
Nicola Corti 9f0903780b Bump monorepo packages to 0.82.0-main (#52706)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52706

This just prepares the repo for the next branch cut.

Changelog:
[Internal] [Changed] -

Reviewed By: cipolleschi

Differential Revision: D78558445

fbshipit-source-id: 2132d560dad447b3685874438387a519587f8554
2025-07-18 09:23:10 -07:00
generatedunixname89002005287564 ae3b793de6 Fix CQS signal modernize-use-using in xplat/js/react-native-github/packages [A] [A] (#52708)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52708

Reviewed By: rshest

Differential Revision: D78538428

fbshipit-source-id: 6195ead0fa36e5fc4632e9a57362508f55969380
2025-07-18 09:01:22 -07:00
generatedunixname1395667395051502 37a0517b3f Update React Native DevTools binaries
Summary:
Automated update of React Native DevTools binaries
bypass-github-export-checks
Changelog: [Internal]

Reviewed By: robhogan

Differential Revision: D78413554

fbshipit-source-id: 5b0d64f886db4cf121f4a6761e6a3e7fe1ccceec
2025-07-18 08:54:36 -07:00
generatedunixname89002005287564 e186f1bf17 Fix CQS signal modernize-use-using in xplat/js/react-native-github/packages [B] (#52693)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52693

Reviewed By: dtolnay

Differential Revision: D78494711

fbshipit-source-id: 870e300b29e41aec488926cdf416f246de96514d
2025-07-18 08:28:34 -07:00
Nicola Corti eb2461c7c9 Create a debugOptimized buildType for Android (#52648)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52648

This creates a `debugOptimized` build type for React Native Android, meaning that we can run C++ optimization on the debug build, while still having the debugger enabled. This is aimed at improving the developer experience for folks developing on low-end devices or emulators.

Users that intend to debug can still use the `debug` variant where the full debug symbols are shipped.

Changelog:

[ANDROID] [ADDED] - Create a debugOptimized buildType for Android

Reviewed By: cipolleschi

Differential Revision: D78425138

fbshipit-source-id: c1e9ea3608e7df10fb871a5584352f0747cf560b
2025-07-18 08:07:54 -07:00
Nicola Corti d89acc1596 Migrate helloworld to use {usesCleartextTraffic} manifest placeholder (#52647)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52647

This removes the need to specify 2 Manifests for apps and we can just use the `main` manifes to toggle if `usesCleartextTraffic` should be enabled or not.

This will have to be replicated in the template repository.

Changelog:
[Android] [Added] - Add support to specify a single Manifest rather than 2 (main/debug) by using the `usesCleartextTraffic` manifest placeholder which is autoconfigured by RNGP.

Reviewed By: cipolleschi

Differential Revision: D78425139

fbshipit-source-id: 9173a014b387d5aed5f7087fa69b7bd49c220f2c
2025-07-18 08:07:54 -07:00
Nicola Corti 5e3edafec6 Migrate RNTester to use {usesCleartextTraffic} Manifest Placeholder (#52620)
Summary:
This creates a `debugOptimized` build type for React Native Android, meaning that we can run C++ optimization on the debug build, while still having the debugger enabled. This is aimed at improving the developer experience for folks developing on low-end devices or emulators.

Users that intend to debug can still use the `debug` variant where the full debug symbols are shipped.

## Changelog:

[ANDROID] [ADDED] - Create a debugOptimized buildType for Android

Pull Request resolved: https://github.com/facebook/react-native/pull/52620

Test Plan:
Tested locally with RNTester by doing:

```
./gradlew installDebugOptimized
```

This is the output of the 3 generated .aar. The size difference is a proof that we're correctly stripping out the C++ debug symbols:

<img width="193" height="54" alt="Screenshot 2025-07-15 at 17 49 50" src="https://github.com/user-attachments/assets/584a0e8d-2d17-40d4-ac29-da09049d6554" />
<img width="235" height="51" alt="Screenshot 2025-07-15 at 17 49 39" src="https://github.com/user-attachments/assets/eda8f9e7-3509-4334-8c16-990e55caa04d" />
<img width="184" height="52" alt="Screenshot 2025-07-15 at 17 49 32" src="https://github.com/user-attachments/assets/a5c94385-bc00-4484-b43e-088ee039827f" />

Rollback Plan:

Reviewed By: cipolleschi

Differential Revision: D78351347

Pulled By: cortinico

fbshipit-source-id: 568a484ba8d2ee6e089cabc95451938e853fbc54
2025-07-18 08:07:54 -07:00
71 changed files with 493 additions and 184 deletions
-36
View File
@@ -1,36 +0,0 @@
{
"arrowParens": "avoid",
"bracketSameLine": true,
"bracketSpacing": false,
"requirePragma": true,
"singleQuote": true,
"trailingComma": "all",
"endOfLine": "lf",
"overrides": [
{
"files": ["*.code-workspace"],
"options": {
"parser": "json"
}
},
{
"files": [
"*.js",
"*.js.flow"
],
"options": {
"parser": "hermes"
}
},
{
"files": [
"**/__docs__/*.md"
],
"options": {
"parser": "markdown",
"proseWrap": "always",
"requirePragma": false
}
}
]
}
+48
View File
@@ -0,0 +1,48 @@
/**
* 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.
*
* @format
*/
module.exports = {
arrowParens: 'avoid',
bracketSameLine: true,
bracketSpacing: false,
requirePragma: true,
singleQuote: true,
trailingComma: 'all',
endOfLine: 'lf',
plugins: [
// Using module.parent and createRequire hack to simulate prettier v2 plugin resolution behavior.
// The hack allows us to resolve the plugin from the install location of prettier.
(module.parent
? require('module').createRequire(module.parent.id)
: require
).resolve('prettier-plugin-hermes-parser'),
],
overrides: [
{
files: ['*.code-workspace'],
options: {
parser: 'json',
},
},
{
files: ['*.js', '*.js.flow'],
options: {
parser: 'hermes',
},
},
{
files: ['**/__docs__/*.md'],
options: {
parser: 'markdown',
proseWrap: 'always',
requirePragma: false,
},
},
],
};
+2 -2
View File
@@ -56,8 +56,8 @@
"@electron/packager": "^18.3.6",
"@jest/create-cache-key-function": "^29.7.0",
"@microsoft/api-extractor": "^7.52.2",
"@react-native/metro-babel-transformer": "0.81.0-main",
"@react-native/metro-config": "0.81.0-main",
"@react-native/metro-babel-transformer": "0.82.0-main",
"@react-native/metro-config": "0.82.0-main",
"@tsconfig/node22": "22.0.2",
"@types/react": "^19.1.0",
"@typescript-eslint/parser": "^8.36.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/assets-registry",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Asset support code for React Native.",
"license": "MIT",
"repository": {
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/babel-plugin-codegen",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Babel plugin to generate native module and view manager code for React Native.",
"license": "MIT",
"repository": {
@@ -26,7 +26,7 @@
],
"dependencies": {
"@babel/traverse": "^7.25.3",
"@react-native/codegen": "0.81.0-main"
"@react-native/codegen": "0.82.0-main"
},
"devDependencies": {
"@babel/core": "^7.25.2"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/community-cli-plugin",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Core CLI commands for React Native",
"keywords": [
"react-native",
@@ -22,7 +22,7 @@
"dist"
],
"dependencies": {
"@react-native/dev-middleware": "0.81.0-main",
"@react-native/dev-middleware": "0.82.0-main",
"debug": "^4.4.0",
"invariant": "^2.2.4",
"metro": "^0.83.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/core-cli-utils",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "React Native CLI library for Frameworks to build on",
"license": "MIT",
"main": "./src/index.flow.js",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/debugger-frontend",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Debugger frontend for React Native based on Chrome DevTools",
"keywords": [
"react-native",
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env dotslash
// @generated SignedSource<<686df5695b32a90cd465412d979a1a3f>>
{
"name": "React Native DevTools",
"platforms": {
"linux-aarch64": {
"size": 113511487,
"hash": "sha256",
"digest": "c22f7d5e029357f05055ce7c56cc284a0d441d558e103a7b7ebae118c67d0b95",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPRilWDJV8xyKEv9lqYn7Hf2kyZg6nqW8KctGZCXsU95lS_MTFyAmEULrB3J6hGCjqBY2Zl-uq_FjERAIgzbZFWX2eceacTbutBSOKEj6QTZzkVN_L1zPh2lGh24x29MHpkwUzw4E-kAXV43f-11QxqD7orI1QicyOnsmUqeRNKE_QjM9rNRsw6iE8"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-arm64/React Native DevTools"
},
"linux-x86_64": {
"size": 113244728,
"hash": "sha256",
"digest": "d749aee18d6c969f033511ed631b439c578068cc20786974bc0ee707c6c2f177",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQP8NAAXjHJ-9NJThip1nnmVim4yiS1tdYAXmWl2Remiluq5f13nXA8YEadsmGRLWxXz2WJouHXSK47ea4a30fxewyKeTt0niFn3T-lr_91m3Ve5ZS-FOZ_9CRVCkv5zC-Z1FlXJGOnphfWetIU10Pw9tho3IzjdSNlXle0XTrkJ2AyKSl4cKPaX"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-x64/React Native DevTools"
},
"macos-aarch64": {
"size": 108805847,
"hash": "sha256",
"digest": "dc4a6cfa3d2d8646db8793ef497e43ad72be54bb14ed96345d059880ff72ce1e",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPuZx9G4h30mUDM0hZ8y74LbzAi7-S6jnOqq8uyfDdIptLwIgpb8CKB8F2tduvaBFMGd7obwXd2NVy01r6XKVdgAK5-QTp8PYUPUE7VSCi6QAqobXcQ2uq_lY-jgyj8XkV4Ua4gA6KR609Bmh-beSTOrSqMymqVodaGqoGjB_9jVwfD99_PfFlex-Ta"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"macos-x86_64": {
"size": 113766610,
"hash": "sha256",
"digest": "74178859ce6a1c26c32055e192b1b123822c76c827ea86a6dfdb5463b89b1ace",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQN6DjGhr8_L7N_cwrh8pi3cfNcbn9dot_QQpgwe3Vv-780FDgi6JUeMvbo_wbFoT2rogxfHZ0-NbXbKdWYwhGUoGeQuikT57QnVMOYuPUTjlQUgYy0Ng9XPhq3iSEYwlMV1XsUJuPFRUg-hIHcgaaA55JoTLXZ1fLYydhHnmgRxGHc4pxaHvSpTtQ"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/debugger-shell",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Experimental debugger shell for React Native for use with @react-native/debugger-frontend",
"keywords": [
"react-native",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/dev-middleware",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Dev server middleware for React Native",
"keywords": [
"react-native",
@@ -23,7 +23,7 @@
],
"dependencies": {
"@isaacs/ttlcache": "^1.4.1",
"@react-native/debugger-frontend": "0.81.0-main",
"@react-native/debugger-frontend": "0.82.0-main",
"chrome-launcher": "^0.15.2",
"chromium-edge-launcher": "^0.2.0",
"connect": "^3.6.5",
@@ -1,6 +1,6 @@
{
"name": "@react-native/eslint-config",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "ESLint config for React Native",
"license": "MIT",
"repository": {
@@ -22,7 +22,7 @@
"dependencies": {
"@babel/core": "^7.25.2",
"@babel/eslint-parser": "^7.25.1",
"@react-native/eslint-plugin": "0.81.0-main",
"@react-native/eslint-plugin": "0.82.0-main",
"@typescript-eslint/eslint-plugin": "^8.36.0",
"@typescript-eslint/parser": "^8.36.0",
"eslint-config-prettier": "^8.5.0",
@@ -1,6 +1,6 @@
{
"name": "@react-native/eslint-plugin",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "ESLint rules for @react-native/eslint-config",
"license": "MIT",
"repository": {
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/eslint-plugin-specs",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "ESLint rules to validate NativeModule and Component Specs",
"license": "MIT",
"repository": {
@@ -26,7 +26,7 @@
"dependencies": {
"@babel/core": "^7.25.2",
"@babel/plugin-transform-flow-strip-types": "^7.25.2",
"@react-native/codegen": "0.81.0-main",
"@react-native/codegen": "0.82.0-main",
"make-dir": "^2.1.0",
"pirates": "^4.0.1",
"source-map-support": "0.5.0"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/gradle-plugin",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Gradle Plugin for React Native",
"license": "MIT",
"repository": {
@@ -100,10 +100,10 @@ abstract class ReactExtension @Inject constructor(val project: Project) {
* Allows to specify the debuggable variants (by default just 'debug'). Variants in this list will
* not be bundled (the bundle file will not be created and won't be copied over).
*
* Default: ['debug']
* Default: ['debug', 'debugOptimized']
*/
val debuggableVariants: ListProperty<String> =
objects.listProperty(String::class.java).convention(listOf("debug"))
objects.listProperty(String::class.java).convention(listOf("debug", "debugOptimized"))
/** Hermes Config */
@@ -42,6 +42,16 @@ internal object AgpConfiguratorUtils {
getByName("release").apply {
manifestPlaceholders["usesCleartextTraffic"] = "false"
}
maybeCreate("debugOptimized").apply {
manifestPlaceholders["usesCleartextTraffic"] = "true"
initWith(debug)
externalNativeBuild {
cmake {
arguments("-DCMAKE_BUILD_TYPE=Release")
matchingFallbacks += listOf("release")
}
}
}
}
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/metro-config",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Metro configuration for React Native.",
"license": "MIT",
"repository": {
@@ -26,8 +26,8 @@
"dist"
],
"dependencies": {
"@react-native/js-polyfills": "0.81.0-main",
"@react-native/metro-babel-transformer": "0.81.0-main",
"@react-native/js-polyfills": "0.82.0-main",
"@react-native/metro-babel-transformer": "0.82.0-main",
"metro-config": "^0.83.0",
"metro-runtime": "^0.83.0"
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/new-app-screen",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "NewAppScreen component for React Native",
"keywords": [
"react-native"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/normalize-colors",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Color normalization for React Native.",
"license": "MIT",
"repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/js-polyfills",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Polyfills for React Native.",
"license": "MIT",
"repository": {
@@ -1,6 +1,6 @@
{
"name": "@react-native/babel-preset",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Babel preset for React Native applications",
"repository": {
"type": "git",
@@ -66,7 +66,7 @@
"@babel/plugin-transform-typescript": "^7.25.2",
"@babel/plugin-transform-unicode-regex": "^7.24.7",
"@babel/template": "^7.25.0",
"@react-native/babel-plugin-codegen": "0.81.0-main",
"@react-native/babel-plugin-codegen": "0.82.0-main",
"babel-plugin-syntax-hermes-parser": "0.29.1",
"babel-plugin-transform-flow-enums": "^0.0.2",
"react-refresh": "^0.14.0"
@@ -1,6 +1,6 @@
{
"name": "@react-native/metro-babel-transformer",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Babel transformer for React Native applications.",
"repository": {
"type": "git",
@@ -27,7 +27,7 @@
],
"dependencies": {
"@babel/core": "^7.25.2",
"@react-native/babel-preset": "0.81.0-main",
"@react-native/babel-preset": "0.82.0-main",
"hermes-parser": "0.29.1",
"nullthrows": "^1.1.1"
},
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/codegen",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Code generation tools for React Native",
"license": "MIT",
"repository": {
@@ -1,6 +1,6 @@
{
"name": "@react-native/compatibility-check",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Check a React Native app's boundary between JS and Native for incompatibilities",
"license": "MIT",
"repository": {
@@ -29,7 +29,7 @@
"dist"
],
"dependencies": {
"@react-native/codegen": "0.81.0-main"
"@react-native/codegen": "0.82.0-main"
},
"devDependencies": {
"flow-remove-types": "^2.237.2",
@@ -1,6 +1,6 @@
{
"name": "@react-native/popup-menu-android",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "PopupMenu for the Android platform",
"main": "index.js",
"files": [
@@ -21,7 +21,7 @@
},
"license": "MIT",
"devDependencies": {
"@react-native/codegen": "0.81.0-main"
"@react-native/codegen": "0.82.0-main"
},
"peerDependencies": {
"@types/react": "^19.1.0",
@@ -1,6 +1,6 @@
{
"name": "@react-native/oss-library-example",
"version": "0.81.0-main",
"version": "0.82.0-main",
"private": true,
"description": "Package that includes native module exapmle, native component example, targets both the old and the new architecture. It should serve as an example of a real-world OSS library.",
"license": "MIT",
@@ -26,7 +26,7 @@
],
"devDependencies": {
"@babel/core": "^7.25.2",
"@react-native/babel-preset": "0.81.0-main",
"@react-native/babel-preset": "0.82.0-main",
"react-native": "1000.0.0"
},
"peerDependencies": {
@@ -50,8 +50,9 @@ class LazyVector {
const_reference at(size_type pos) const {
#ifndef _LIBCPP_NO_EXCEPTIONS
if (!(pos < _size))
if (!(pos < _size)) {
throw std::out_of_range("out of range");
}
#else
assert(pos < _size || !"out of range");
#endif
@@ -25,11 +25,13 @@ static NSUInteger RCTDeviceFreeMemory(void)
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS)
if (kern != KERN_SUCCESS) {
return 0;
}
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS)
if (kern != KERN_SUCCESS) {
return 0;
}
return (vm_stat.free_count - vm_stat.speculative_count) * page_size;
}
@@ -278,8 +280,9 @@ static NSUInteger RCTDeviceFreeMemory(void)
- (void)calculateMaxBufferCount
{
NSUInteger bytes = CGImageGetBytesPerRow(self.currentFrame.CGImage) * CGImageGetHeight(self.currentFrame.CGImage);
if (bytes == 0)
if (bytes == 0) {
bytes = 1024;
}
NSUInteger max = 0;
if (self.maxBufferSize > 0) {
@@ -66,7 +66,7 @@
static NSString *const RCTJSThreadName = @"com.facebook.react.JavaScript";
typedef void (^RCTPendingCall)();
using RCTPendingCall = void (^)();
using namespace facebook::jsi;
using namespace facebook::react;
@@ -11,11 +11,11 @@
#import <jsinspector-modern/ReactCdp.h>
typedef facebook::react::jsinspector_modern::NetworkRequestListener RCTInspectorNetworkListener;
using RCTInspectorNetworkListener = facebook::react::jsinspector_modern::NetworkRequestListener;
typedef facebook::react::jsinspector_modern::ScopedExecutor<RCTInspectorNetworkListener> RCTInspectorNetworkExecutor;
using RCTInspectorNetworkExecutor = facebook::react::jsinspector_modern::ScopedExecutor<RCTInspectorNetworkListener>;
typedef facebook::react::jsinspector_modern::LoadNetworkResourceRequest RCTInspectorLoadNetworkResourceRequest;
using RCTInspectorLoadNetworkResourceRequest = facebook::react::jsinspector_modern::LoadNetworkResourceRequest;
/**
* A helper class that wraps around NSURLSession to make network requests.
@@ -8,7 +8,7 @@
#import "RCTInspectorNetworkHelper.h"
#import <React/RCTLog.h>
typedef void (^ListenerBlock)(RCTInspectorNetworkListener *);
using ListenerBlock = void (^)(RCTInspectorNetworkListener *);
@interface RCTInspectorNetworkHelper () <NSURLSessionDataDelegate>
@property (nonatomic, strong) NSURLSession *session;
+2 -2
View File
@@ -205,7 +205,7 @@ RCT_ENUM_CONVERTER(
UIFontWeightRegular,
doubleValue)
typedef BOOL RCTFontStyle;
using RCTFontStyle = BOOL;
RCT_ENUM_CONVERTER(
RCTFontStyle,
(@{
@@ -216,7 +216,7 @@ RCT_ENUM_CONVERTER(
NO,
boolValue)
typedef NSDictionary RCTFontVariantDescriptor;
using RCTFontVariantDescriptor = NSDictionary;
+ (RCTFontVariantDescriptor *)RCTFontVariantDescriptor:(id)json
{
static NSDictionary *mapping;
@@ -71,8 +71,9 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
- (void)beginRefreshingProgrammatically
{
if (!_hasMovedToWindow)
if (!_hasMovedToWindow) {
return;
}
UInt64 beginRefreshingTimestamp = _currentRefreshingStateTimestamp;
_refreshingProgrammatically = YES;
@@ -108,8 +109,9 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
- (void)endRefreshingProgrammatically
{
if (!_hasMovedToWindow)
if (!_hasMovedToWindow) {
return;
}
// The contentOffset of the scrollview MUST be greater than the contentInset before calling
// endRefreshing otherwise the next pull to refresh will not work properly.
UIScrollView *scrollView = self.scrollView;
@@ -599,7 +599,7 @@ android {
publishing {
multipleVariants {
withSourcesJar()
includeBuildTypeValues("debug", "release")
includeBuildTypeValues("debug", "release", "debugOptimized")
}
}
@@ -607,6 +607,15 @@ android {
unitTests { isIncludeAndroidResources = true }
targetSdk = libs.versions.targetSdk.get().toInt()
}
buildTypes {
create("debugOptimized") {
initWith(getByName("debug"))
externalNativeBuild {
cmake { arguments("-DCMAKE_BUILD_TYPE=Release", "-DREACT_NATIVE_DEBUG_OPTIMIZED=True") }
}
}
}
}
tasks.withType<KotlinCompile>().configureEach {
@@ -306,6 +306,12 @@ android {
}
}
}
buildTypes {
create("debugOptimized") {
initWith(getByName("debug"))
externalNativeBuild { cmake { arguments("-DCMAKE_BUILD_TYPE=Release") } }
}
}
}
sourceSets.getByName("main") {
@@ -675,6 +675,18 @@ public class FabricUIManager
: null);
}
@AnyThread
@ThreadConfined(ANY)
@UnstableReactNativeAPI
public PreparedLayout reusePreparedLayoutWithNewReactTags(
PreparedLayout preparedLayout, int[] reactTags) {
return new PreparedLayout(
preparedLayout.getLayout(),
preparedLayout.getMaximumNumberOfLines(),
preparedLayout.getVerticalOffset(),
reactTags);
}
@AnyThread
@ThreadConfined(ANY)
@UnstableReactNativeAPI
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<c8b19934d19d6b4514a0395edecb1330>>
* @generated SignedSource<<93aab733661b558c1701b728c18b3d00>>
*/
/**
@@ -23,5 +23,5 @@ public open class ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android :
// We could use JNI to get the defaults from C++,
// but that is more expensive than just duplicating the defaults here.
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean = true
}
@@ -407,6 +407,9 @@ public class ReactScrollView extends ScrollView
if (mMaintainVisibleContentPositionHelper != null) {
mMaintainVisibleContentPositionHelper.stop();
}
if (mVirtualViewContainerState != null) {
mVirtualViewContainerState.cleanup();
}
}
@Override
@@ -9,6 +9,7 @@ package com.facebook.react.views.scroll
import android.graphics.Rect
import android.view.ViewGroup
import android.view.ViewTreeObserver
import com.facebook.common.logging.FLog
import com.facebook.react.common.build.ReactBuildConfig
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
@@ -46,13 +47,34 @@ private fun rectsOverlap(rect1: Rect, rect2: Rect): Boolean {
return true
}
internal class VirtualViewContainerState(private val scrollView: ViewGroup) {
internal class VirtualViewContainerState {
private val prerenderRatio: Double = ReactNativeFeatureFlags.virtualViewPrerenderRatio()
private val detectWindowFocus = ReactNativeFeatureFlags.enableVirtualViewWindowFocusDetection()
private val virtualViews: MutableSet<VirtualView> = mutableSetOf()
private val emptyRect: Rect = Rect()
private val visibleRect: Rect = Rect()
private val prerenderRect: Rect = Rect()
private val onWindowFocusChangeListener =
ViewTreeObserver.OnWindowFocusChangeListener {
debugLog("onWindowFocusChanged")
updateModes()
}
private val scrollView: ViewGroup
constructor(scrollView: ViewGroup) {
this.scrollView = scrollView
if (detectWindowFocus) {
scrollView.viewTreeObserver.addOnWindowFocusChangeListener(onWindowFocusChangeListener)
}
}
public fun cleanup() {
if (detectWindowFocus) {
scrollView.viewTreeObserver.removeOnWindowFocusChangeListener(onWindowFocusChangeListener)
}
}
public fun onChange(virtualView: VirtualView) {
if (virtualViews.add(virtualView)) {
@@ -72,7 +94,7 @@ internal class VirtualViewContainerState(private val scrollView: ViewGroup) {
// Called on ScrollView onLayout or onScroll
public fun updateState() {
debugLog("VirtualViewContainer.updateState")
debugLog("updateState")
updateModes()
}
@@ -92,8 +114,16 @@ internal class VirtualViewContainerState(private val scrollView: ViewGroup) {
when {
rect.isEmpty -> {}
rectsOverlap(rect, visibleRect) -> {
mode = VirtualViewMode.Visible
thresholdRect = visibleRect
if (detectWindowFocus) {
if (scrollView.hasWindowFocus()) {
mode = VirtualViewMode.Visible
} else {
mode = VirtualViewMode.Prerender
}
} else {
mode = VirtualViewMode.Visible
}
}
rectsOverlap(rect, prerenderRect) -> {
mode = VirtualViewMode.Prerender
@@ -115,7 +145,7 @@ private val IS_DEBUG_BUILD =
ReactBuildConfig.DEBUG || ReactBuildConfig.IS_INTERNAL_BUILD || ReactBuildConfig.ENABLE_PERFETTO
internal inline fun debugLog(subtag: String, block: () -> String = { "" }) {
if (IS_DEBUG_BUILD) {
if (IS_DEBUG_BUILD && ReactNativeFeatureFlags.enableVirtualViewDebugFeatures()) {
FLog.d("$DEBUG_TAG:$subtag", block())
}
}
@@ -18,5 +18,6 @@ import com.facebook.proguard.annotations.DoNotStrip
internal class PreparedLayout(
val layout: Layout,
val maximumNumberOfLines: Int,
val verticalOffset: Float
val verticalOffset: Float,
val reactTags: IntArray,
)
@@ -27,7 +27,7 @@ import com.facebook.proguard.annotations.DoNotStrip
import com.facebook.react.uimanager.BackgroundStyleApplicator
import com.facebook.react.uimanager.ReactCompoundView
import com.facebook.react.uimanager.style.Overflow
import com.facebook.react.views.text.internal.span.ReactTagSpan
import com.facebook.react.views.text.internal.span.ReactFragmentIndexSpan
import kotlin.collections.ArrayList
import kotlin.math.roundToInt
@@ -310,8 +310,9 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
override fun hasOverlappingRendering(): Boolean = false
override fun reactTagForTouch(touchX: Float, touchY: Float): Int =
getSpanInCoords(touchX.roundToInt(), touchY.roundToInt(), ReactTagSpan::class.java)?.reactTag
?: id
getSpanInCoords(touchX.roundToInt(), touchY.roundToInt(), ReactFragmentIndexSpan::class.java)
?.fragmentIndex
?.let { preparedLayout?.reactTags[it] } ?: id
@RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
private object Api34Utils {
@@ -42,6 +42,8 @@ import com.facebook.react.views.text.internal.span.ReactAbsoluteSizeSpan
import com.facebook.react.views.text.internal.span.ReactBackgroundColorSpan
import com.facebook.react.views.text.internal.span.ReactClickableSpan
import com.facebook.react.views.text.internal.span.ReactForegroundColorSpan
import com.facebook.react.views.text.internal.span.ReactFragmentIndexSpan
import com.facebook.react.views.text.internal.span.ReactLinkSpan
import com.facebook.react.views.text.internal.span.ReactOpacitySpan
import com.facebook.react.views.text.internal.span.ReactStrikethroughSpan
import com.facebook.react.views.text.internal.span.ReactTagSpan
@@ -218,7 +220,8 @@ internal object TextLayoutManager {
context: Context,
fragments: MapBuffer,
sb: SpannableStringBuilder,
ops: MutableList<SetSpanOperation>
ops: MutableList<SetSpanOperation>,
outputReactTags: IntArray?
) {
for (i in 0 until fragments.count) {
val fragment = fragments.getMapBuffer(i)
@@ -249,7 +252,11 @@ internal object TextLayoutManager {
(textAttributes.mAccessibilityRole ==
ReactAccessibilityDelegate.AccessibilityRole.LINK)
if (roleIsLink) {
ops.add(SetSpanOperation(start, end, ReactClickableSpan(reactTag)))
if (ReactNativeFeatureFlags.enablePreparedTextLayout()) {
ops.add(SetSpanOperation(start, end, ReactLinkSpan(i)))
} else {
ops.add(SetSpanOperation(start, end, ReactClickableSpan(reactTag)))
}
}
if (textAttributes.mIsColorSet) {
ops.add(SetSpanOperation(start, end, ReactForegroundColorSpan(textAttributes.mColor)))
@@ -307,7 +314,14 @@ internal object TextLayoutManager {
start, end, CustomLineHeightSpan(textAttributes.effectiveLineHeight)))
}
ops.add(SetSpanOperation(start, end, ReactTagSpan(reactTag)))
if (ReactNativeFeatureFlags.enablePreparedTextLayout()) {
ops.add(SetSpanOperation(start, end, ReactFragmentIndexSpan(i)))
if (outputReactTags != null) {
outputReactTags[i] = reactTag
}
} else {
ops.add(SetSpanOperation(start, end, ReactTagSpan(reactTag)))
}
}
}
}
@@ -323,7 +337,8 @@ internal object TextLayoutManager {
private fun buildSpannableFromFragmentsOptimized(
context: Context,
fragments: MapBuffer
fragments: MapBuffer,
outputReactTags: IntArray?
): Spannable {
val text = StringBuilder()
val parsedFragments = ArrayList<FragmentAttributes>(fragments.count)
@@ -363,7 +378,7 @@ internal object TextLayoutManager {
val spannable = SpannableString(text)
var start = 0
for (fragment in parsedFragments) {
for ((i, fragment) in parsedFragments.withIndex()) {
val end = start + fragment.length
val spanFlags =
if (start == 0) Spannable.SPAN_INCLUSIVE_INCLUSIVE else Spannable.SPAN_EXCLUSIVE_INCLUSIVE
@@ -386,7 +401,11 @@ internal object TextLayoutManager {
ReactAccessibilityDelegate.AccessibilityRole.LINK)
if (roleIsLink) {
spannable.setSpan(ReactClickableSpan(fragment.reactTag), start, end, spanFlags)
if (ReactNativeFeatureFlags.enablePreparedTextLayout()) {
spannable.setSpan(ReactLinkSpan(i), start, end, spanFlags)
} else {
spannable.setSpan(ReactClickableSpan(fragment.reactTag), start, end, spanFlags)
}
}
if (fragment.props.isColorSet) {
@@ -453,7 +472,14 @@ internal object TextLayoutManager {
CustomLineHeightSpan(fragment.props.effectiveLineHeight), start, end, spanFlags)
}
spannable.setSpan(ReactTagSpan(fragment.reactTag), start, end, spanFlags)
if (ReactNativeFeatureFlags.enablePreparedTextLayout()) {
spannable.setSpan(ReactFragmentIndexSpan(i), start, end, spanFlags)
if (outputReactTags != null) {
outputReactTags[i] = fragment.reactTag
}
} else {
spannable.setSpan(ReactTagSpan(fragment.reactTag), start, end, spanFlags)
}
}
start = end
@@ -474,7 +500,10 @@ internal object TextLayoutManager {
} else {
text =
createSpannableFromAttributedString(
context, attributedString, reactTextViewManagerCallback)
context,
attributedString.getMapBuffer(AS_KEY_FRAGMENTS),
reactTextViewManagerCallback,
null)
}
return text
@@ -482,13 +511,12 @@ internal object TextLayoutManager {
private fun createSpannableFromAttributedString(
context: Context,
attributedString: MapBuffer,
reactTextViewManagerCallback: ReactTextViewManagerCallback?
fragments: MapBuffer,
reactTextViewManagerCallback: ReactTextViewManagerCallback?,
outputReactTags: IntArray?
): Spannable {
if (ReactNativeFeatureFlags.enableAndroidTextMeasurementOptimizations()) {
val spannable =
buildSpannableFromFragmentsOptimized(
context, attributedString.getMapBuffer(AS_KEY_FRAGMENTS))
val spannable = buildSpannableFromFragmentsOptimized(context, fragments, outputReactTags)
reactTextViewManagerCallback?.onPostProcessSpannable(spannable)
return spannable
@@ -500,7 +528,7 @@ internal object TextLayoutManager {
// a new spannable will be wiped out
val ops: MutableList<SetSpanOperation> = ArrayList()
buildSpannableFromFragments(context, attributedString.getMapBuffer(AS_KEY_FRAGMENTS), sb, ops)
buildSpannableFromFragments(context, fragments, sb, ops, outputReactTags)
// TODO T31905686: add support for inline Images
// While setting the Spans on the final text, we also check whether any of them are images.
@@ -756,7 +784,11 @@ internal object TextLayoutManager {
heightYogaMeasureMode: YogaMeasureMode,
reactTextViewManagerCallback: ReactTextViewManagerCallback?
): PreparedLayout {
val text = getOrCreateSpannableForText(context, attributedString, reactTextViewManagerCallback)
val fragments = attributedString.getMapBuffer(AS_KEY_FRAGMENTS)
val reactTags = IntArray(fragments.count)
val text =
createSpannableFromAttributedString(
context, fragments, reactTextViewManagerCallback, reactTags)
val baseTextAttributes =
TextAttributeProps.fromMapBuffer(attributedString.getMapBuffer(AS_KEY_BASE_ATTRIBUTES))
val layout =
@@ -779,7 +811,7 @@ internal object TextLayoutManager {
getVerticalOffset(
layout, paragraphAttributes, height, heightYogaMeasureMode, maximumNumberOfLines)
return PreparedLayout(layout, maximumNumberOfLines, verticalOffset)
return PreparedLayout(layout, maximumNumberOfLines, verticalOffset, reactTags)
}
@JvmStatic
@@ -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.
*/
package com.facebook.react.views.text.internal.span
/**
* Maps a section of the text to the index of the AttributedString fragment originally used to
* create it.
*/
internal class ReactFragmentIndexSpan(val fragmentIndex: Int) : ReactSpan
@@ -0,0 +1,47 @@
/*
* 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.views.text.internal.span
import android.text.TextPaint
import android.text.style.ClickableSpan
import android.view.View
import com.facebook.react.bridge.ReactContext
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.views.text.PreparedLayoutTextView
import com.facebook.react.views.text.TextLayoutManager
import com.facebook.react.views.view.ViewGroupClickEvent
/**
* This class is used in [TextLayoutManager] to linkify and style a span of text with
* accessibilityRole="link". This is needed to make nested Text components accessible.
*
* For example, if your React component looks like this:
* ```js
* <Text>
* Some text with
* <Text onPress={onPress} accessible={true} accessibilityRole="link">a link</Text>
* in the middle.
* </Text>
* ```
*/
internal class ReactLinkSpan(val fragmentIndex: Int) : ClickableSpan(), ReactSpan {
override fun onClick(view: View) {
val context = view.context as ReactContext
val textView = view as? PreparedLayoutTextView ?: return
val preparedLayout = textView.preparedLayout ?: return
val reactTag = preparedLayout.reactTags[fragmentIndex]
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, reactTag)
eventDispatcher?.dispatchEvent(
ViewGroupClickEvent(UIManagerHelper.getSurfaceId(context), reactTag))
}
override fun updateDrawState(ds: TextPaint) {
// no super call so we don't change the link color or add an underline by default, as the
// superclass does.
}
}
@@ -15,6 +15,7 @@ import androidx.annotation.VisibleForTesting
import com.facebook.common.logging.FLog
import com.facebook.react.R
import com.facebook.react.common.build.ReactBuildConfig
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
import com.facebook.react.uimanager.ReactRoot
import com.facebook.react.views.scroll.VirtualView
import com.facebook.react.views.scroll.VirtualViewContainer
@@ -202,7 +203,7 @@ public class ReactVirtualViewExperimental(context: Context) :
}
internal inline fun debugLog(subtag: String, block: () -> String = { "" }) {
if (IS_DEBUG_BUILD) {
if (IS_DEBUG_BUILD && ReactNativeFeatureFlags.enableVirtualViewDebugFeatures()) {
FLog.d("$DEBUG_TAG:$subtag", "${block()} [$id][$nativeId]")
}
}
@@ -25,4 +25,6 @@ target_link_libraries(
reactnative
)
target_compile_reactnative_options(hermes_executor PRIVATE)
target_compile_options(hermes_executor PRIVATE $<$<CONFIG:Debug>:-DHERMES_ENABLE_DEBUGGER=1>)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(hermes_executor PRIVATE -DHERMES_ENABLE_DEBUGGER=1)
endif()
@@ -27,4 +27,6 @@ target_link_libraries(hermesinstancejni
)
target_compile_reactnative_options(hermesinstancejni PRIVATE)
target_compile_options(hermesinstancejni PRIVATE $<$<CONFIG:Debug>:-DHERMES_ENABLE_DEBUGGER=1>)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(hermesinstancejni PRIVATE -DHERMES_ENABLE_DEBUGGER=1)
endif ()
@@ -17,7 +17,9 @@ add_library(rninstance
)
target_compile_reactnative_options(rninstance PRIVATE)
target_compile_options(rninstance PRIVATE $<$<CONFIG:Debug>:-DHERMES_ENABLE_DEBUGGER=1>)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(rninstance PRIVATE -DHERMES_ENABLE_DEBUGGER=1)
endif ()
target_merge_so(rninstance)
target_include_directories(rninstance PUBLIC .)
@@ -53,9 +53,9 @@ class CxxModule {
class SyncTagType {};
public:
typedef std::function<std::unique_ptr<CxxModule>()> Provider;
using Provider = std::function<std::unique_ptr<CxxModule>()>;
typedef std::function<void(std::vector<folly::dynamic>)> Callback;
using Callback = std::function<void(std::vector<folly::dynamic>)>;
constexpr static AsyncTagType AsyncTag = AsyncTagType();
constexpr static SyncTagType SyncTag = SyncTagType();
@@ -68,8 +68,8 @@ namespace detail {
// only for types compatible with folly::dynamic.
template <typename T>
struct is_dynamic {
typedef typename std::
enable_if<std::is_assignable<folly::dynamic, T>::value, T>::type type;
using type = typename std::
enable_if<std::is_assignable<folly::dynamic, T>::value, T>::type;
};
} // end namespace detail
@@ -16,8 +16,9 @@ using namespace facebook::react;
namespace {
int tempFileFromString(std::string contents) {
const char* tmpDir = getenv("TMPDIR");
if (tmpDir == nullptr)
if (tmpDir == nullptr) {
tmpDir = "/tmp";
}
std::string tmp{tmpDir};
tmp += "/temp.XXXXXX";
@@ -26,7 +26,7 @@ target_link_libraries(hermes_executor_common
)
target_compile_reactnative_options(hermes_executor_common PRIVATE)
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(
hermes_executor_common
PRIVATE
@@ -17,7 +17,7 @@ add_library(hermes_inspector_modern
target_compile_reactnative_options(hermes_inspector_modern PRIVATE)
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(
hermes_inspector_modern
PRIVATE
@@ -28,7 +28,9 @@ target_link_libraries(jsinspector
reactperflogger
)
target_compile_reactnative_options(jsinspector PRIVATE)
target_compile_options(jsinspector PRIVATE
$<$<CONFIG:Debug>:-DREACT_NATIVE_DEBUGGER_ENABLED=1>
$<$<CONFIG:Debug>:-DREACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1>
)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(jsinspector PRIVATE
-DREACT_NATIVE_DEBUGGER_ENABLED=1
-DREACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1
)
endif ()
@@ -14,7 +14,7 @@ enum ReactNativeLogLevel {
ReactNativeLogLevelFatal = 4
};
typedef void (*reactnativelogfunctype)(ReactNativeLogLevel, const char*);
using reactnativelogfunctype = void (*)(ReactNativeLogLevel, const char*);
#ifdef __cplusplus
extern "C" {
@@ -21,6 +21,6 @@ endif()
target_compile_reactnative_options(react_debug PRIVATE)
target_compile_options(react_debug PRIVATE -Wpedantic)
if(NOT ${CMAKE_BUILD_TYPE} MATCHES Debug)
if(NOT ${CMAKE_BUILD_TYPE} MATCHES Debug AND NOT REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(react_debug PUBLIC -DNDEBUG)
endif()
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<1de02178e1be302bb4b19501950b260a>>
* @generated SignedSource<<16c5fdf431579bbfd454a28c06f28c41>>
*/
/**
@@ -27,7 +27,9 @@ class ReactNativeFeatureFlagsOverridesOSSExperimental : public ReactNativeFeatur
public:
ReactNativeFeatureFlagsOverridesOSSExperimental() = default;
bool preventShadowTreeCommitExhaustionWithLocking() override {
return true;
}
};
} // namespace facebook::react
@@ -190,7 +190,8 @@ TextMeasurement TextLayoutManager::measure(
};
auto measurement =
ReactNativeFeatureFlags::disableTextLayoutManagerCacheAndroid()
(ReactNativeFeatureFlags::disableTextLayoutManagerCacheAndroid() ||
ReactNativeFeatureFlags::enablePreparedTextLayout())
? measureText()
: textMeasureCache_.get(
{.attributedString = attributedString,
@@ -310,14 +311,19 @@ TextLayoutManager::PreparedLayout TextLayoutManager::prepareLayout(
jfloat,
jfloat)>("prepareTextLayout");
return preparedTextCache_.get(
static auto reusePreparedLayoutWithNewReactTags =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<JPreparedLayout::javaobject(
JPreparedLayout::javaobject, jintArray)>(
"reusePreparedLayoutWithNewReactTags");
const auto [key, preparedText] = preparedTextCache_.getWithKey(
{.attributedString = attributedString,
.paragraphAttributes = paragraphAttributes,
.layoutConstraints = layoutConstraints},
[&] {
[&]() {
const auto& fabricUIManager =
contextContainer_->at<jni::global_ref<jobject>>("FabricUIManager");
auto attributedStringMB = JReadableMapBuffer::createWithContents(
toMapBuffer(attributedString));
auto paragraphAttributesMB = JReadableMapBuffer::createWithContents(
@@ -336,6 +342,39 @@ TextLayoutManager::PreparedLayout TextLayoutManager::prepareLayout(
minimumSize.height,
maximumSize.height))};
});
// PreparedTextCacheKey allows equality of layouts which are the same
// display-wise, but ShadowView fragments (and thus react tags) may have
// changed.
const auto& fragments = attributedString.getFragments();
const auto& cacheKeyFragments = key->attributedString.getFragments();
bool needsNewReactTags = [&] {
for (size_t i = 0; i < fragments.size(); i++) {
if (fragments[i].parentShadowView.tag !=
cacheKeyFragments[i].parentShadowView.tag) {
return true;
}
}
return false;
}();
if (needsNewReactTags) {
std::vector<int> reactTags(fragments.size());
for (size_t i = 0; i < reactTags.size(); i++) {
reactTags[i] = fragments[i].parentShadowView.tag;
}
auto javaReactTags = jni::JArrayInt::newArray(fragments.size());
javaReactTags->setRegion(
0, static_cast<jsize>(reactTags.size()), reactTags.data());
const auto& fabricUIManager =
contextContainer_->at<jni::global_ref<jobject>>("FabricUIManager");
return PreparedLayout{jni::make_global(reusePreparedLayoutWithNewReactTags(
fabricUIManager, preparedText->get(), javaReactTags.get()))};
} else {
return PreparedLayout{*preparedText};
}
}
TextMeasurement TextLayoutManager::measurePreparedLayout(
@@ -16,7 +16,9 @@ add_library(bridgeless
${bridgeless_SRC}
)
target_compile_reactnative_options(bridgeless PRIVATE)
target_compile_options(bridgeless PRIVATE $<$<CONFIG:Debug>:-DHERMES_ENABLE_DEBUGGER=1>)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(bridgeless PRIVATE -DHERMES_ENABLE_DEBUGGER=1)
endif ()
target_include_directories(bridgeless PUBLIC .)
react_native_android_selector(fabricjni fabricjni "")
@@ -29,7 +29,7 @@ target_link_libraries(bridgelesshermes
)
target_compile_reactnative_options(bridgelesshermes PRIVATE)
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(
bridgelesshermes
PRIVATE
@@ -38,24 +38,20 @@ class SimpleThreadSafeCache {
*/
ValueT get(const KeyT& key, CacheGeneratorFunction<ValueT> auto generator)
const {
std::lock_guard<std::mutex> lock(mutex_);
return getMapIterator(key, std::move(generator))->second->second;
}
if (auto it = map_.find(key); it != map_.end()) {
// Move accessed item to front of list
list_.splice(list_.begin(), list_, it->second);
return it->second->second;
}
auto value = generator();
// Add new value to front of list and map
list_.emplace_front(key, value);
map_[key] = list_.begin();
if (list_.size() > maxSize_) {
// Evict least recently used item (back of list)
map_.erase(list_.back().first);
list_.pop_back();
}
return value;
/*
* Returns pointers to both the key and value from the map with a given key.
* If the value wasn't found in the cache, constructs the value using given
* generator function, stores it inside a cache and returns it.
* Can be called from any thread.
*/
std::pair<const KeyT*, const ValueT*> getWithKey(
const KeyT& key,
CacheGeneratorFunction<ValueT> auto generator) const {
auto it = getMapIterator(key, std::move(generator));
return std::make_pair(&it->first, &it->second->second);
}
/*
@@ -79,6 +75,29 @@ class SimpleThreadSafeCache {
using EntryT = std::pair<KeyT, ValueT>;
using iterator = typename std::list<EntryT>::iterator;
auto getMapIterator(
const KeyT& key,
CacheGeneratorFunction<ValueT> auto generator) const {
std::lock_guard<std::mutex> lock(mutex_);
if (auto it = map_.find(key); it != map_.end()) {
// Move accessed item to front of list
list_.splice(list_.begin(), list_, it->second);
return it;
}
auto value = generator();
// Add new value to front of list and map
list_.emplace_front(key, value);
auto [it, _] = map_.insert_or_assign(key, list_.begin());
if (list_.size() > maxSize_) {
// Evict least recently used item (back of list)
map_.erase(list_.back().first);
list_.pop_back();
}
return it;
}
size_t maxSize_;
mutable std::mutex mutex_;
mutable std::list<EntryT> list_;
+7 -7
View File
@@ -161,13 +161,13 @@
},
"dependencies": {
"@jest/create-cache-key-function": "^29.7.0",
"@react-native/assets-registry": "0.81.0-main",
"@react-native/codegen": "0.81.0-main",
"@react-native/community-cli-plugin": "0.81.0-main",
"@react-native/gradle-plugin": "0.81.0-main",
"@react-native/js-polyfills": "0.81.0-main",
"@react-native/normalize-colors": "0.81.0-main",
"@react-native/virtualized-lists": "0.81.0-main",
"@react-native/assets-registry": "0.82.0-main",
"@react-native/codegen": "0.82.0-main",
"@react-native/community-cli-plugin": "0.82.0-main",
"@react-native/gradle-plugin": "0.82.0-main",
"@react-native/js-polyfills": "0.82.0-main",
"@react-native/normalize-colors": "0.82.0-main",
"@react-native/virtualized-lists": "0.82.0-main",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
"ansi-regex": "^5.0.0",
@@ -545,7 +545,7 @@ const definitions: FeatureFlagDefinitions = {
expectedReleaseValue: true,
purpose: 'experimentation',
},
ossReleaseStage: 'none',
ossReleaseStage: 'experimental',
},
releaseImageDataWhenConsumed: {
defaultValue: false,
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/tester",
"version": "0.81.0-main",
"version": "0.82.0-main",
"private": true,
"description": "React Native tester app.",
"license": "MIT",
@@ -26,9 +26,9 @@
"e2e-test-ios": "./scripts/maestro-test-ios.sh"
},
"dependencies": {
"@react-native/oss-library-example": "0.81.0-main",
"@react-native/new-app-screen": "0.81.0-main",
"@react-native/popup-menu-android": "0.81.0-main",
"@react-native/oss-library-example": "0.82.0-main",
"@react-native/new-app-screen": "0.82.0-main",
"@react-native/popup-menu-android": "0.82.0-main",
"flow-enums-runtime": "^0.0.6",
"invariant": "^2.2.4",
"nullthrows": "^1.1.1"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/typescript-config",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Default TypeScript configuration for React Native apps",
"license": "MIT",
"repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@react-native/virtualized-lists",
"version": "0.81.0-main",
"version": "0.82.0-main",
"description": "Virtualized lists for React Native.",
"license": "MIT",
"repository": {
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:usesCleartextTraffic="true"
tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning"/>
</manifest>
@@ -8,6 +8,7 @@
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:usesCleartextTraffic="${usesCleartextTraffic}"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
+5 -5
View File
@@ -19,11 +19,11 @@
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/runtime": "^7.25.0",
"@react-native/babel-preset": "0.81.0-main",
"@react-native/core-cli-utils": "0.81.0-main",
"@react-native/eslint-config": "0.81.0-main",
"@react-native/metro-config": "0.81.0-main",
"@react-native/typescript-config": "0.81.0-main",
"@react-native/babel-preset": "0.82.0-main",
"@react-native/core-cli-utils": "0.82.0-main",
"@react-native/eslint-config": "0.82.0-main",
"@react-native/metro-config": "0.82.0-main",
"@react-native/typescript-config": "0.82.0-main",
"@types/jest": "^29.5.14",
"commander": "^12.0.0",
"eslint": "^8.19.0",
@@ -13,7 +13,7 @@
"prepare": "yarn run build"
},
"dependencies": {
"@react-native/codegen": "0.81.0-main"
"@react-native/codegen": "0.82.0-main"
},
"devDependencies": {
"@babel/core": "^7.25.2",