diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index 43ca6dc4f166..52ed16a20766 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt @@ -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<<99a7d3e814f4b037ed4496b6eee4f264>> + * @generated SignedSource<<45d368406f020ca101d9b87c7e2527b1>> */ /** @@ -444,6 +444,18 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun preventShadowTreeCommitExhaustion(): Boolean = accessor.preventShadowTreeCommitExhaustion() + /** + * Use the redesigned RedBox error overlay on Android, styled to match the LogBox visual language. + */ + @JvmStatic + public fun redBoxV2Android(): Boolean = accessor.redBoxV2Android() + + /** + * Use the redesigned RedBox error overlay on iOS, styled to match the LogBox visual language. + */ + @JvmStatic + public fun redBoxV2IOS(): Boolean = accessor.redBoxV2IOS() + /** * Function used to enable / disable Pressibility from using W3C Pointer Events for its hover callbacks */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index be22235e4470..1d78c66ea5a3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt @@ -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<> + * @generated SignedSource<<5bb0640a99befcfcb3a197a5a074513f>> */ /** @@ -89,6 +89,8 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces private var perfMonitorV2EnabledCache: Boolean? = null private var preparedTextCacheSizeCache: Double? = null private var preventShadowTreeCommitExhaustionCache: Boolean? = null + private var redBoxV2AndroidCache: Boolean? = null + private var redBoxV2IOSCache: Boolean? = null private var shouldPressibilityUseW3CPointerEventsForHoverCache: Boolean? = null private var shouldTriggerResponderTransferOnScrollAndroidCache: Boolean? = null private var skipActivityIdentityAssertionOnHostPauseCache: Boolean? = null @@ -731,6 +733,24 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun redBoxV2Android(): Boolean { + var cached = redBoxV2AndroidCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.redBoxV2Android() + redBoxV2AndroidCache = cached + } + return cached + } + + override fun redBoxV2IOS(): Boolean { + var cached = redBoxV2IOSCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.redBoxV2IOS() + redBoxV2IOSCache = cached + } + return cached + } + override fun shouldPressibilityUseW3CPointerEventsForHover(): Boolean { var cached = shouldPressibilityUseW3CPointerEventsForHoverCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index 2ba162535ac8..8fa95c07d631 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt @@ -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<<8667d7237cea82bb5978cb19582d59c0>> + * @generated SignedSource<<23c20167823efb1df8209cdffa7a23d0>> */ /** @@ -166,6 +166,10 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun preventShadowTreeCommitExhaustion(): Boolean + @DoNotStrip @JvmStatic public external fun redBoxV2Android(): Boolean + + @DoNotStrip @JvmStatic public external fun redBoxV2IOS(): Boolean + @DoNotStrip @JvmStatic public external fun shouldPressibilityUseW3CPointerEventsForHover(): Boolean @DoNotStrip @JvmStatic public external fun shouldTriggerResponderTransferOnScrollAndroid(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index 0bd08cd5665c..fbed6ccb5204 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -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<<17abc72a4045c5695818f254be1783b5>> + * @generated SignedSource<> */ /** @@ -161,6 +161,10 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun preventShadowTreeCommitExhaustion(): Boolean = false + override fun redBoxV2Android(): Boolean = false + + override fun redBoxV2IOS(): Boolean = false + override fun shouldPressibilityUseW3CPointerEventsForHover(): Boolean = false override fun shouldTriggerResponderTransferOnScrollAndroid(): Boolean = false diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index b2e5d18cd8df..5bed35bd2230 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt @@ -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<<77ba6c5db120016e6e1f8af195ab3690>> + * @generated SignedSource<<7d3853cb7e319830aab97792e1520ff7>> */ /** @@ -93,6 +93,8 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc private var perfMonitorV2EnabledCache: Boolean? = null private var preparedTextCacheSizeCache: Double? = null private var preventShadowTreeCommitExhaustionCache: Boolean? = null + private var redBoxV2AndroidCache: Boolean? = null + private var redBoxV2IOSCache: Boolean? = null private var shouldPressibilityUseW3CPointerEventsForHoverCache: Boolean? = null private var shouldTriggerResponderTransferOnScrollAndroidCache: Boolean? = null private var skipActivityIdentityAssertionOnHostPauseCache: Boolean? = null @@ -804,6 +806,26 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun redBoxV2Android(): Boolean { + var cached = redBoxV2AndroidCache + if (cached == null) { + cached = currentProvider.redBoxV2Android() + accessedFeatureFlags.add("redBoxV2Android") + redBoxV2AndroidCache = cached + } + return cached + } + + override fun redBoxV2IOS(): Boolean { + var cached = redBoxV2IOSCache + if (cached == null) { + cached = currentProvider.redBoxV2IOS() + accessedFeatureFlags.add("redBoxV2IOS") + redBoxV2IOSCache = cached + } + return cached + } + override fun shouldPressibilityUseW3CPointerEventsForHover(): Boolean { var cached = shouldPressibilityUseW3CPointerEventsForHoverCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index 41ce962f044a..0d67ebb124f5 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -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<<8496c138ce5493df84149940df0de944>> + * @generated SignedSource<> */ /** @@ -161,6 +161,10 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun preventShadowTreeCommitExhaustion(): Boolean + @DoNotStrip public fun redBoxV2Android(): Boolean + + @DoNotStrip public fun redBoxV2IOS(): Boolean + @DoNotStrip public fun shouldPressibilityUseW3CPointerEventsForHover(): Boolean @DoNotStrip public fun shouldTriggerResponderTransferOnScrollAndroid(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index c176fb1b7631..60f22a831bbb 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -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<<5bac13bb6faeffdd3c5eca800f25b96a>> + * @generated SignedSource<> */ /** @@ -453,6 +453,18 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool redBoxV2Android() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("redBoxV2Android"); + return method(javaProvider_); + } + + bool redBoxV2IOS() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("redBoxV2IOS"); + return method(javaProvider_); + } + bool shouldPressibilityUseW3CPointerEventsForHover() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("shouldPressibilityUseW3CPointerEventsForHover"); @@ -922,6 +934,16 @@ bool JReactNativeFeatureFlagsCxxInterop::preventShadowTreeCommitExhaustion( return ReactNativeFeatureFlags::preventShadowTreeCommitExhaustion(); } +bool JReactNativeFeatureFlagsCxxInterop::redBoxV2Android( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::redBoxV2Android(); +} + +bool JReactNativeFeatureFlagsCxxInterop::redBoxV2IOS( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::redBoxV2IOS(); +} + bool JReactNativeFeatureFlagsCxxInterop::shouldPressibilityUseW3CPointerEventsForHover( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::shouldPressibilityUseW3CPointerEventsForHover(); @@ -1260,6 +1282,12 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "preventShadowTreeCommitExhaustion", JReactNativeFeatureFlagsCxxInterop::preventShadowTreeCommitExhaustion), + makeNativeMethod( + "redBoxV2Android", + JReactNativeFeatureFlagsCxxInterop::redBoxV2Android), + makeNativeMethod( + "redBoxV2IOS", + JReactNativeFeatureFlagsCxxInterop::redBoxV2IOS), makeNativeMethod( "shouldPressibilityUseW3CPointerEventsForHover", JReactNativeFeatureFlagsCxxInterop::shouldPressibilityUseW3CPointerEventsForHover), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index d02c0855a993..b1584ffd7ac4 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -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<> + * @generated SignedSource<> */ /** @@ -237,6 +237,12 @@ class JReactNativeFeatureFlagsCxxInterop static bool preventShadowTreeCommitExhaustion( facebook::jni::alias_ref); + static bool redBoxV2Android( + facebook::jni::alias_ref); + + static bool redBoxV2IOS( + facebook::jni::alias_ref); + static bool shouldPressibilityUseW3CPointerEventsForHover( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 43076de959a4..e7468c18996d 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -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<> + * @generated SignedSource<<211e6d3081b5fc5e5b30e87f04970e95>> */ /** @@ -302,6 +302,14 @@ bool ReactNativeFeatureFlags::preventShadowTreeCommitExhaustion() { return getAccessor().preventShadowTreeCommitExhaustion(); } +bool ReactNativeFeatureFlags::redBoxV2Android() { + return getAccessor().redBoxV2Android(); +} + +bool ReactNativeFeatureFlags::redBoxV2IOS() { + return getAccessor().redBoxV2IOS(); +} + bool ReactNativeFeatureFlags::shouldPressibilityUseW3CPointerEventsForHover() { return getAccessor().shouldPressibilityUseW3CPointerEventsForHover(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 8ba43c099206..5b89b63eea48 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -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<<86b3267ffa68e0f68280957aa54d5041>> + * @generated SignedSource<<4adf6fb186eeb45234b8c1196e9a92c9>> */ /** @@ -384,6 +384,16 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool preventShadowTreeCommitExhaustion(); + /** + * Use the redesigned RedBox error overlay on Android, styled to match the LogBox visual language. + */ + RN_EXPORT static bool redBoxV2Android(); + + /** + * Use the redesigned RedBox error overlay on iOS, styled to match the LogBox visual language. + */ + RN_EXPORT static bool redBoxV2IOS(); + /** * Function used to enable / disable Pressibility from using W3C Pointer Events for its hover callbacks */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 1f40889efc0d..5a23f350c170 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -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<<218ab046c336961b8220c48eb0426b7f>> + * @generated SignedSource<> */ /** @@ -1271,6 +1271,42 @@ bool ReactNativeFeatureFlagsAccessor::preventShadowTreeCommitExhaustion() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::redBoxV2Android() { + auto flagValue = redBoxV2Android_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(69, "redBoxV2Android"); + + flagValue = currentProvider_->redBoxV2Android(); + redBoxV2Android_ = flagValue; + } + + return flagValue.value(); +} + +bool ReactNativeFeatureFlagsAccessor::redBoxV2IOS() { + auto flagValue = redBoxV2IOS_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(70, "redBoxV2IOS"); + + flagValue = currentProvider_->redBoxV2IOS(); + redBoxV2IOS_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::shouldPressibilityUseW3CPointerEventsForHover() { auto flagValue = shouldPressibilityUseW3CPointerEventsForHover_.load(); @@ -1280,7 +1316,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldPressibilityUseW3CPointerEventsForHo // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(69, "shouldPressibilityUseW3CPointerEventsForHover"); + markFlagAsAccessed(71, "shouldPressibilityUseW3CPointerEventsForHover"); flagValue = currentProvider_->shouldPressibilityUseW3CPointerEventsForHover(); shouldPressibilityUseW3CPointerEventsForHover_ = flagValue; @@ -1298,7 +1334,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldTriggerResponderTransferOnScrollAndr // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(70, "shouldTriggerResponderTransferOnScrollAndroid"); + markFlagAsAccessed(72, "shouldTriggerResponderTransferOnScrollAndroid"); flagValue = currentProvider_->shouldTriggerResponderTransferOnScrollAndroid(); shouldTriggerResponderTransferOnScrollAndroid_ = flagValue; @@ -1316,7 +1352,7 @@ bool ReactNativeFeatureFlagsAccessor::skipActivityIdentityAssertionOnHostPause() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(71, "skipActivityIdentityAssertionOnHostPause"); + markFlagAsAccessed(73, "skipActivityIdentityAssertionOnHostPause"); flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause(); skipActivityIdentityAssertionOnHostPause_ = flagValue; @@ -1334,7 +1370,7 @@ bool ReactNativeFeatureFlagsAccessor::syncAndroidClipToPaddingWithOverflow() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(72, "syncAndroidClipToPaddingWithOverflow"); + markFlagAsAccessed(74, "syncAndroidClipToPaddingWithOverflow"); flagValue = currentProvider_->syncAndroidClipToPaddingWithOverflow(); syncAndroidClipToPaddingWithOverflow_ = flagValue; @@ -1352,7 +1388,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(73, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(75, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -1370,7 +1406,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit( // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(74, "updateRuntimeShadowNodeReferencesOnCommit"); + markFlagAsAccessed(76, "updateRuntimeShadowNodeReferencesOnCommit"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit(); updateRuntimeShadowNodeReferencesOnCommit_ = flagValue; @@ -1388,7 +1424,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommitT // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(75, "updateRuntimeShadowNodeReferencesOnCommitThread"); + markFlagAsAccessed(77, "updateRuntimeShadowNodeReferencesOnCommitThread"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommitThread(); updateRuntimeShadowNodeReferencesOnCommitThread_ = flagValue; @@ -1406,7 +1442,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(76, "useAlwaysAvailableJSErrorHandling"); + markFlagAsAccessed(78, "useAlwaysAvailableJSErrorHandling"); flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling(); useAlwaysAvailableJSErrorHandling_ = flagValue; @@ -1424,7 +1460,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(77, "useFabricInterop"); + markFlagAsAccessed(79, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -1442,7 +1478,7 @@ bool ReactNativeFeatureFlagsAccessor::useLISAlgorithmInDifferentiator() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(78, "useLISAlgorithmInDifferentiator"); + markFlagAsAccessed(80, "useLISAlgorithmInDifferentiator"); flagValue = currentProvider_->useLISAlgorithmInDifferentiator(); useLISAlgorithmInDifferentiator_ = flagValue; @@ -1460,7 +1496,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(79, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(81, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -1478,7 +1514,7 @@ bool ReactNativeFeatureFlagsAccessor::useNestedScrollViewAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(80, "useNestedScrollViewAndroid"); + markFlagAsAccessed(82, "useNestedScrollViewAndroid"); flagValue = currentProvider_->useNestedScrollViewAndroid(); useNestedScrollViewAndroid_ = flagValue; @@ -1496,7 +1532,7 @@ bool ReactNativeFeatureFlagsAccessor::useSharedAnimatedBackend() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(81, "useSharedAnimatedBackend"); + markFlagAsAccessed(83, "useSharedAnimatedBackend"); flagValue = currentProvider_->useSharedAnimatedBackend(); useSharedAnimatedBackend_ = flagValue; @@ -1514,7 +1550,7 @@ bool ReactNativeFeatureFlagsAccessor::useTraitHiddenOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(82, "useTraitHiddenOnAndroid"); + markFlagAsAccessed(84, "useTraitHiddenOnAndroid"); flagValue = currentProvider_->useTraitHiddenOnAndroid(); useTraitHiddenOnAndroid_ = flagValue; @@ -1532,7 +1568,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(83, "useTurboModuleInterop"); + markFlagAsAccessed(85, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -1550,7 +1586,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(84, "useTurboModules"); + markFlagAsAccessed(86, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; @@ -1568,7 +1604,7 @@ bool ReactNativeFeatureFlagsAccessor::useUnorderedMapInDifferentiator() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(85, "useUnorderedMapInDifferentiator"); + markFlagAsAccessed(87, "useUnorderedMapInDifferentiator"); flagValue = currentProvider_->useUnorderedMapInDifferentiator(); useUnorderedMapInDifferentiator_ = flagValue; @@ -1586,7 +1622,7 @@ double ReactNativeFeatureFlagsAccessor::viewCullingOutsetRatio() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(86, "viewCullingOutsetRatio"); + markFlagAsAccessed(88, "viewCullingOutsetRatio"); flagValue = currentProvider_->viewCullingOutsetRatio(); viewCullingOutsetRatio_ = flagValue; @@ -1604,7 +1640,7 @@ bool ReactNativeFeatureFlagsAccessor::viewTransitionEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(87, "viewTransitionEnabled"); + markFlagAsAccessed(89, "viewTransitionEnabled"); flagValue = currentProvider_->viewTransitionEnabled(); viewTransitionEnabled_ = flagValue; @@ -1622,7 +1658,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(88, "virtualViewPrerenderRatio"); + markFlagAsAccessed(90, "virtualViewPrerenderRatio"); flagValue = currentProvider_->virtualViewPrerenderRatio(); virtualViewPrerenderRatio_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 7b83ec509d66..73c4cecf8fc8 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -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<> + * @generated SignedSource<<33b0bb5aac0966483d6163484aae10a3>> */ /** @@ -101,6 +101,8 @@ class ReactNativeFeatureFlagsAccessor { bool perfMonitorV2Enabled(); double preparedTextCacheSize(); bool preventShadowTreeCommitExhaustion(); + bool redBoxV2Android(); + bool redBoxV2IOS(); bool shouldPressibilityUseW3CPointerEventsForHover(); bool shouldTriggerResponderTransferOnScrollAndroid(); bool skipActivityIdentityAssertionOnHostPause(); @@ -132,7 +134,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 89> accessedFeatureFlags_; + std::array, 91> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> cdpInteractionMetricsEnabled_; @@ -203,6 +205,8 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> perfMonitorV2Enabled_; std::atomic> preparedTextCacheSize_; std::atomic> preventShadowTreeCommitExhaustion_; + std::atomic> redBoxV2Android_; + std::atomic> redBoxV2IOS_; std::atomic> shouldPressibilityUseW3CPointerEventsForHover_; std::atomic> shouldTriggerResponderTransferOnScrollAndroid_; std::atomic> skipActivityIdentityAssertionOnHostPause_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index b6f431af8f0e..a67085d1e7c2 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -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<<33fd238aafa83c5a42803d3f11d55944>> + * @generated SignedSource<<4ea6e74132f9879a727e4b85e6baa3fc>> */ /** @@ -303,6 +303,14 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool redBoxV2Android() override { + return false; + } + + bool redBoxV2IOS() override { + return false; + } + bool shouldPressibilityUseW3CPointerEventsForHover() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index 0d48c7d05074..1c0da695ba04 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h @@ -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<<2a95ea2091c8e73816acf12daf5e2408>> + * @generated SignedSource<<41290a5bebdecf9c3be32341a79b0317>> */ /** @@ -666,6 +666,24 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::preventShadowTreeCommitExhaustion(); } + bool redBoxV2Android() override { + auto value = values_["redBoxV2Android"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::redBoxV2Android(); + } + + bool redBoxV2IOS() override { + auto value = values_["redBoxV2IOS"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::redBoxV2IOS(); + } + bool shouldPressibilityUseW3CPointerEventsForHover() override { auto value = values_["shouldPressibilityUseW3CPointerEventsForHover"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index a6246efc165a..8943d02cf1ca 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -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<> + * @generated SignedSource<<89c9431802f2653efb73f160b5ac9608>> */ /** @@ -94,6 +94,8 @@ class ReactNativeFeatureFlagsProvider { virtual bool perfMonitorV2Enabled() = 0; virtual double preparedTextCacheSize() = 0; virtual bool preventShadowTreeCommitExhaustion() = 0; + virtual bool redBoxV2Android() = 0; + virtual bool redBoxV2IOS() = 0; virtual bool shouldPressibilityUseW3CPointerEventsForHover() = 0; virtual bool shouldTriggerResponderTransferOnScrollAndroid() = 0; virtual bool skipActivityIdentityAssertionOnHostPause() = 0; diff --git a/packages/react-native/ReactCommon/react/featureflags/rewrite_feature_flag_defaults.py b/packages/react-native/ReactCommon/react/featureflags/rewrite_feature_flag_defaults.py new file mode 100644 index 000000000000..ed146edd4534 --- /dev/null +++ b/packages/react-native/ReactCommon/react/featureflags/rewrite_feature_flag_defaults.py @@ -0,0 +1,79 @@ +#!/usr/bin/env fbpython +# 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. + +# pyre-strict + +"""Rewrite default return values in ReactNativeFeatureFlagsDefaults.h. + +Reads the header from --input, writes the transformed header to stdout. +Overrides are passed as a JSON object via --overrides. +Fails with a non-zero exit code if any requested flag is not found. +""" + +from __future__ import annotations + +import argparse +import json +import re +import sys + + +def cxx_literal(value: object) -> str: + if isinstance(value, bool): + return "true" if value else "false" + if isinstance(value, (int, float)): + s = str(value) + if isinstance(value, int) or "." not in s: + s += ".0" + return s + raise ValueError(f"Unsupported value type {type(value).__name__} for override") + + +def rewrite(source: bytes, overrides: dict[str, object]) -> bytes: + text = source.decode("utf-8") + for name, value in overrides.items(): + cxx_type = "bool" if isinstance(value, bool) else "double" + pattern = rf""" + ( # group 1: everything up to the value + {cxx_type} \s+ # return type + {re.escape(name)} # method name + \s* \( \s* \) # parameter list + \s+ override # override specifier + \s* \{{ # opening brace + [^}}]*? # body before the return (non-greedy, no nested braces) + return \s+ # return keyword + ) + [^;]+ # the value to replace + ( \s* ; ) # group 2: semicolon + """ + text, n = re.subn( + pattern, + rf"\g<1>{cxx_literal(value)}\2", + text, + count=1, + flags=re.DOTALL | re.VERBOSE, + ) + if n != 1: + raise ValueError(f"{name} not matched") + + return text.encode("utf-8") + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--overrides", default="{}") + parser.add_argument("--input", required=True) + args = parser.parse_args() + + overrides: dict[str, object] = json.loads(args.overrides) + with open(args.input, "rb") as f: + source = f.read() + + sys.stdout.buffer.write(rewrite(source, overrides)) + + +if __name__ == "__main__": + main() diff --git a/packages/react-native/ReactCommon/react/featureflags/tests/test_rewrite_feature_flag_defaults.py b/packages/react-native/ReactCommon/react/featureflags/tests/test_rewrite_feature_flag_defaults.py new file mode 100644 index 000000000000..3483ba3b725e --- /dev/null +++ b/packages/react-native/ReactCommon/react/featureflags/tests/test_rewrite_feature_flag_defaults.py @@ -0,0 +1,60 @@ +# 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. + +# pyre-strict + +from __future__ import annotations + +import os +import unittest + +from rewrite_feature_flag_defaults import cxx_literal, rewrite + + +def _load_header() -> bytes: + with open(os.environ["HEADER_PATH"], "rb") as f: + return f.read() + + +class RewriteFeatureFlagDefaultsTest(unittest.TestCase): + def setUp(self) -> None: + self.source = _load_header() + + def test_empty_overrides_is_passthrough(self) -> None: + self.assertEqual(rewrite(self.source, {}), self.source) + + def test_override_bool_to_true(self) -> None: + result = rewrite(self.source, {"commonTestFlag": True}) + start, end = self._method_body_range(result, "commonTestFlag") + self.assertIn(b"return true;", result[start:end]) + + def test_override_bool_to_false(self) -> None: + result = rewrite(self.source, {"commonTestFlag": False}) + start, end = self._method_body_range(result, "commonTestFlag") + self.assertIn(b"return false;", result[start:end]) + + def test_cxx_literal_int_produces_double(self) -> None: + self.assertEqual(cxx_literal(42), "42.0") + + def test_cxx_literal_float(self) -> None: + self.assertEqual(cxx_literal(3.14), "3.14") + + def test_unmatched_flag_raises(self) -> None: + with self.assertRaises(ValueError): + rewrite(self.source, {"bogusFlag": True}) + + def test_only_target_method_body_changes(self) -> None: + result = rewrite(self.source, {"commonTestFlag": True}) + src_start, src_end = self._method_body_range(self.source, "commonTestFlag") + res_start, res_end = self._method_body_range(result, "commonTestFlag") + self.assertEqual(self.source[:src_start], result[:res_start]) + self.assertEqual(self.source[src_end:], result[res_end:]) + + def _method_body_range(self, source: bytes, name: str) -> tuple[int, int]: + idx = source.find(name.encode()) + self.assertNotEqual(idx, -1, f"{name} not found in output") + open_brace = source.find(b"{", idx) + close_brace = source.find(b"}", open_brace) + return (open_brace, close_brace + 1) diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 2e9a936b9e1e..27265764d993 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -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<<3d49e243422f2c220ab36f3e32a78e38>> + * @generated SignedSource<<48e9d8e58caa8fd45c380153714d1166>> */ /** @@ -389,6 +389,16 @@ bool NativeReactNativeFeatureFlags::preventShadowTreeCommitExhaustion( return ReactNativeFeatureFlags::preventShadowTreeCommitExhaustion(); } +bool NativeReactNativeFeatureFlags::redBoxV2Android( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::redBoxV2Android(); +} + +bool NativeReactNativeFeatureFlags::redBoxV2IOS( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::redBoxV2IOS(); +} + bool NativeReactNativeFeatureFlags::shouldPressibilityUseW3CPointerEventsForHover( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::shouldPressibilityUseW3CPointerEventsForHover(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 9580cbc99d25..d7244eb917f8 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -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<<3e07a28d13e142ba3c734ca111eb4974>> + * @generated SignedSource<> */ /** @@ -174,6 +174,10 @@ class NativeReactNativeFeatureFlags bool preventShadowTreeCommitExhaustion(jsi::Runtime& runtime); + bool redBoxV2Android(jsi::Runtime& runtime); + + bool redBoxV2IOS(jsi::Runtime& runtime); + bool shouldPressibilityUseW3CPointerEventsForHover(jsi::Runtime& runtime); bool shouldTriggerResponderTransferOnScrollAndroid(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 4a1ea7a74db7..853d28924bdd 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -785,6 +785,28 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'experimental', }, + redBoxV2Android: { + defaultValue: false, + metadata: { + dateAdded: '2026-03-25', + description: + 'Use the redesigned RedBox error overlay on Android, styled to match the LogBox visual language.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'none', + }, + redBoxV2IOS: { + defaultValue: false, + metadata: { + dateAdded: '2026-03-25', + description: + 'Use the redesigned RedBox error overlay on iOS, styled to match the LogBox visual language.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'none', + }, shouldPressibilityUseW3CPointerEventsForHover: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index c225edc521d6..c4bb98382822 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -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<> + * @generated SignedSource<> * @flow strict * @noformat */ @@ -116,6 +116,8 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ perfMonitorV2Enabled: Getter, preparedTextCacheSize: Getter, preventShadowTreeCommitExhaustion: Getter, + redBoxV2Android: Getter, + redBoxV2IOS: Getter, shouldPressibilityUseW3CPointerEventsForHover: Getter, shouldTriggerResponderTransferOnScrollAndroid: Getter, skipActivityIdentityAssertionOnHostPause: Getter, @@ -478,6 +480,14 @@ export const preparedTextCacheSize: Getter = createNativeFlagGetter('pre * Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again. */ export const preventShadowTreeCommitExhaustion: Getter = createNativeFlagGetter('preventShadowTreeCommitExhaustion', false); +/** + * Use the redesigned RedBox error overlay on Android, styled to match the LogBox visual language. + */ +export const redBoxV2Android: Getter = createNativeFlagGetter('redBoxV2Android', false); +/** + * Use the redesigned RedBox error overlay on iOS, styled to match the LogBox visual language. + */ +export const redBoxV2IOS: Getter = createNativeFlagGetter('redBoxV2IOS', false); /** * Function used to enable / disable Pressibility from using W3C Pointer Events for its hover callbacks */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 42ebd77f42e4..a74e55aec9fc 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js @@ -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<<0e66e4ae4407000706cd243ad17aa605>> + * @generated SignedSource<> * @flow strict * @noformat */ @@ -94,6 +94,8 @@ export interface Spec extends TurboModule { +perfMonitorV2Enabled?: () => boolean; +preparedTextCacheSize?: () => number; +preventShadowTreeCommitExhaustion?: () => boolean; + +redBoxV2Android?: () => boolean; + +redBoxV2IOS?: () => boolean; +shouldPressibilityUseW3CPointerEventsForHover?: () => boolean; +shouldTriggerResponderTransferOnScrollAndroid?: () => boolean; +skipActivityIdentityAssertionOnHostPause?: () => boolean;