react-native 0.84.0-nightly-20251118-d314e5f4e → 0.84.0-nightly-20251120-88447cf20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/Libraries/Components/View/ViewPropTypes.js +10 -0
  2. package/Libraries/Core/ReactNativeVersion.js +1 -1
  3. package/Libraries/NativeComponent/BaseViewConfig.android.js +12 -0
  4. package/Libraries/Types/CoreEventTypes.js +31 -0
  5. package/React/Base/RCTVersion.m +1 -1
  6. package/React/CxxModule/RCTCxxUtils.mm +1 -1
  7. package/React/FBReactNativeSpec/FBReactNativeSpecJSI.h +8 -0
  8. package/React/FBReactNativeSpec/react/renderer/components/FBReactNativeSpec/Props.h +14 -0
  9. package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm +6 -0
  10. package/ReactAndroid/api/ReactAndroid.api +2 -14
  11. package/ReactAndroid/gradle.properties +1 -1
  12. package/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +0 -7
  13. package/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.kt +0 -10
  14. package/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +58 -2
  15. package/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.kt +0 -18
  16. package/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +0 -54
  17. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +7 -1
  18. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +11 -1
  19. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +3 -1
  20. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +3 -1
  21. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +12 -1
  22. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +3 -1
  23. package/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.kt +3 -27
  24. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
  25. package/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessCatalystInstance.kt +0 -9
  26. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt +52 -0
  27. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +33 -0
  28. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSKeyDispatcher.kt +65 -0
  29. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java +0 -8
  30. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +0 -8
  31. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java +0 -16
  32. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/KeyDownEvent.kt +23 -0
  33. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/KeyEvent.kt +156 -0
  34. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/KeyUpEvent.kt +24 -0
  35. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +15 -1
  36. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +4 -1
  37. package/ReactAndroid/src/main/jni/react/tracing/PerformanceTracerCxxInterop.cpp +1 -1
  38. package/ReactAndroid/src/main/res/views/uimanager/values-ne/strings.xml +1 -0
  39. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  40. package/ReactCommon/jsi/jsi/test/testlib.cpp +2 -2
  41. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +5 -1
  42. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +6 -1
  43. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +37 -19
  44. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +4 -2
  45. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +5 -1
  46. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +10 -1
  47. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +2 -1
  48. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +6 -1
  49. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +3 -1
  50. package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.cpp +1 -1
  51. package/ReactCommon/react/runtime/ReactInstance.cpp +1 -1
  52. package/index.js.flow +3 -0
  53. package/package.json +9 -9
  54. package/sdks/hermes-engine/version.properties +1 -1
  55. package/src/private/featureflags/ReactNativeFeatureFlags.js +6 -1
  56. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +2 -1
  57. package/types_generated/Libraries/Components/View/ViewPropTypes.d.ts +9 -3
  58. package/types_generated/Libraries/Types/CoreEventTypes.d.ts +29 -1
  59. package/types_generated/index.d.ts +2 -2
  60. package/ReactAndroid/src/main/java/com/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener.kt +0 -36
  61. package/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.kt +0 -157
  62. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.kt +0 -30
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<b2c2e874b05283e0ebd62899f7c417d8>>
7
+ * @generated SignedSource<<15bb2229e65b6a6ae728d512ff51885f>>
8
8
  */
9
9
 
10
10
  /**
@@ -91,6 +91,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
91
91
  private var preventShadowTreeCommitExhaustionCache: Boolean? = null
92
92
  private var shouldPressibilityUseW3CPointerEventsForHoverCache: Boolean? = null
93
93
  private var shouldSetEnabledBasedOnAccessibilityStateCache: Boolean? = null
94
+ private var shouldSetIsClickableByDefaultCache: Boolean? = null
94
95
  private var shouldTriggerResponderTransferOnScrollAndroidCache: Boolean? = null
95
96
  private var skipActivityIdentityAssertionOnHostPauseCache: Boolean? = null
96
97
  private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
@@ -749,6 +750,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
749
750
  return cached
750
751
  }
751
752
 
753
+ override fun shouldSetIsClickableByDefault(): Boolean {
754
+ var cached = shouldSetIsClickableByDefaultCache
755
+ if (cached == null) {
756
+ cached = ReactNativeFeatureFlagsCxxInterop.shouldSetIsClickableByDefault()
757
+ shouldSetIsClickableByDefaultCache = cached
758
+ }
759
+ return cached
760
+ }
761
+
752
762
  override fun shouldTriggerResponderTransferOnScrollAndroid(): Boolean {
753
763
  var cached = shouldTriggerResponderTransferOnScrollAndroidCache
754
764
  if (cached == null) {
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<ccb22ddcd1a76b7c52cf0f1b23e6152b>>
7
+ * @generated SignedSource<<85a6247f6049f60c18efdce5db0cccdf>>
8
8
  */
9
9
 
10
10
  /**
@@ -170,6 +170,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
170
170
 
171
171
  @DoNotStrip @JvmStatic public external fun shouldSetEnabledBasedOnAccessibilityState(): Boolean
172
172
 
173
+ @DoNotStrip @JvmStatic public external fun shouldSetIsClickableByDefault(): Boolean
174
+
173
175
  @DoNotStrip @JvmStatic public external fun shouldTriggerResponderTransferOnScrollAndroid(): Boolean
174
176
 
175
177
  @DoNotStrip @JvmStatic public external fun skipActivityIdentityAssertionOnHostPause(): Boolean
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<30ca2685ceb6f2733531f5e7fce4416d>>
7
+ * @generated SignedSource<<614d228af81090b8b1dee65f4bfb67d7>>
8
8
  */
9
9
 
10
10
  /**
@@ -165,6 +165,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
165
165
 
166
166
  override fun shouldSetEnabledBasedOnAccessibilityState(): Boolean = true
167
167
 
168
+ override fun shouldSetIsClickableByDefault(): Boolean = false
169
+
168
170
  override fun shouldTriggerResponderTransferOnScrollAndroid(): Boolean = false
169
171
 
170
172
  override fun skipActivityIdentityAssertionOnHostPause(): Boolean = false
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<6d1a15e64f42cc7d8869300720276215>>
7
+ * @generated SignedSource<<e4971d843cf79d94f8c61394f4c27204>>
8
8
  */
9
9
 
10
10
  /**
@@ -95,6 +95,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
95
95
  private var preventShadowTreeCommitExhaustionCache: Boolean? = null
96
96
  private var shouldPressibilityUseW3CPointerEventsForHoverCache: Boolean? = null
97
97
  private var shouldSetEnabledBasedOnAccessibilityStateCache: Boolean? = null
98
+ private var shouldSetIsClickableByDefaultCache: Boolean? = null
98
99
  private var shouldTriggerResponderTransferOnScrollAndroidCache: Boolean? = null
99
100
  private var skipActivityIdentityAssertionOnHostPauseCache: Boolean? = null
100
101
  private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
@@ -824,6 +825,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
824
825
  return cached
825
826
  }
826
827
 
828
+ override fun shouldSetIsClickableByDefault(): Boolean {
829
+ var cached = shouldSetIsClickableByDefaultCache
830
+ if (cached == null) {
831
+ cached = currentProvider.shouldSetIsClickableByDefault()
832
+ accessedFeatureFlags.add("shouldSetIsClickableByDefault")
833
+ shouldSetIsClickableByDefaultCache = cached
834
+ }
835
+ return cached
836
+ }
837
+
827
838
  override fun shouldTriggerResponderTransferOnScrollAndroid(): Boolean {
828
839
  var cached = shouldTriggerResponderTransferOnScrollAndroidCache
829
840
  if (cached == null) {
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<48d0d5486793b60914cfd595f0fc78d1>>
7
+ * @generated SignedSource<<e7b49105c0cea6be905be90610f0c7e4>>
8
8
  */
9
9
 
10
10
  /**
@@ -165,6 +165,8 @@ public interface ReactNativeFeatureFlagsProvider {
165
165
 
166
166
  @DoNotStrip public fun shouldSetEnabledBasedOnAccessibilityState(): Boolean
167
167
 
168
+ @DoNotStrip public fun shouldSetIsClickableByDefault(): Boolean
169
+
168
170
  @DoNotStrip public fun shouldTriggerResponderTransferOnScrollAndroid(): Boolean
169
171
 
170
172
  @DoNotStrip public fun skipActivityIdentityAssertionOnHostPause(): Boolean
@@ -26,8 +26,6 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) :
26
26
  Choreographer.FrameCallback {
27
27
 
28
28
  private var choreographer: Choreographer? = null
29
- private val didJSUpdateUiDuringFrameDetector: DidJSUpdateUiDuringFrameDetector =
30
- DidJSUpdateUiDuringFrameDetector()
31
29
  private var firstFrameTime: Long = -1
32
30
  private var lastFrameTime: Long = -1
33
31
  private var numFrameCallbacks = 0
@@ -40,11 +38,7 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) :
40
38
  if (firstFrameTime == -1L) {
41
39
  firstFrameTime = l
42
40
  }
43
- val lastFrameStartTime = lastFrameTime
44
41
  lastFrameTime = l
45
- if (didJSUpdateUiDuringFrameDetector.getDidJSHitFrameAndCleanup(lastFrameStartTime, l)) {
46
- numFrameCallbacksWithBatchDispatches++
47
- }
48
42
  numFrameCallbacks++
49
43
  val expectedNumFrames = expectedNumFrames
50
44
  val framesDropped = expectedNumFrames - expectedNumFramesPrev - 1
@@ -61,17 +55,9 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) :
61
55
  // removeBridgeIdleDebugListener for Bridgeless
62
56
  @Suppress("DEPRECATION")
63
57
  if (!ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE) {
64
- val uiManagerModule =
65
- reactContext.getNativeModule(com.facebook.react.uimanager.UIManagerModule::class.java)
66
- if (!reactContext.isBridgeless) {
67
- reactContext.catalystInstance.addBridgeIdleDebugListener(didJSUpdateUiDuringFrameDetector)
68
- isRunningOnFabric = false
69
- } else {
70
- // T172641976 Consider either implementing a mechanism similar to addBridgeIdleDebugListener
71
- // for Fabric or point users to use RNDT.
72
- isRunningOnFabric = true
73
- }
74
- uiManagerModule?.setViewHierarchyUpdateDebugListener(didJSUpdateUiDuringFrameDetector)
58
+ // T172641976 Consider either implementing a mechanism similar to addBridgeIdleDebugListener
59
+ // for Fabric or point users to use RNDT.
60
+ isRunningOnFabric = true
75
61
  }
76
62
  this.targetFps = targetFps
77
63
  UiThreadUtil.runOnUiThread {
@@ -82,16 +68,6 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) :
82
68
 
83
69
  fun stop() {
84
70
  @Suppress("DEPRECATION")
85
- if (!ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE) {
86
- val uiManagerModule =
87
- reactContext.getNativeModule(com.facebook.react.uimanager.UIManagerModule::class.java)
88
- if (!reactContext.isBridgeless) {
89
- reactContext.catalystInstance.removeBridgeIdleDebugListener(
90
- didJSUpdateUiDuringFrameDetector
91
- )
92
- }
93
- uiManagerModule?.setViewHierarchyUpdateDebugListener(null)
94
- }
95
71
  UiThreadUtil.runOnUiThread {
96
72
  choreographer = Choreographer.getInstance()
97
73
  choreographer?.removeFrameCallback(this)
@@ -15,6 +15,6 @@ public object ReactNativeVersion {
15
15
  "major" to 0,
16
16
  "minor" to 84,
17
17
  "patch" to 0,
18
- "prerelease" to "nightly-20251118-d314e5f4e"
18
+ "prerelease" to "nightly-20251120-88447cf20"
19
19
  )
20
20
  }
@@ -19,7 +19,6 @@ import com.facebook.react.bridge.NativeArray
19
19
  import com.facebook.react.bridge.NativeArrayInterface
20
20
  import com.facebook.react.bridge.NativeModule
21
21
  import com.facebook.react.bridge.NativeModuleRegistry
22
- import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener
23
22
  import com.facebook.react.bridge.RuntimeExecutor
24
23
  import com.facebook.react.bridge.RuntimeScheduler
25
24
  import com.facebook.react.bridge.UIManager
@@ -140,14 +139,6 @@ internal class BridgelessCatalystInstance(private val reactHost: ReactHostImpl)
140
139
  override val sourceURL: String
141
140
  get() = throw UnsupportedOperationException("Unimplemented method 'getSourceURL'")
142
141
 
143
- override fun addBridgeIdleDebugListener(listener: NotThreadSafeBridgeIdleDebugListener) {
144
- throw UnsupportedOperationException("Unimplemented method 'addBridgeIdleDebugListener'")
145
- }
146
-
147
- override fun removeBridgeIdleDebugListener(listener: NotThreadSafeBridgeIdleDebugListener) {
148
- throw UnsupportedOperationException("Unimplemented method 'removeBridgeIdleDebugListener'")
149
- }
150
-
151
142
  override fun registerSegment(segmentId: Int, path: String) {
152
143
  throw UnsupportedOperationException("Unimplemented method 'registerSegment'")
153
144
  }
@@ -12,6 +12,7 @@ package com.facebook.react.runtime
12
12
  import android.content.Context
13
13
  import android.graphics.Point
14
14
  import android.graphics.Rect
15
+ import android.view.KeyEvent
15
16
  import android.view.MotionEvent
16
17
  import android.view.View
17
18
  import com.facebook.common.logging.FLog
@@ -20,7 +21,9 @@ import com.facebook.react.bridge.ReactContext
20
21
  import com.facebook.react.common.annotations.FrameworkAPI
21
22
  import com.facebook.react.common.annotations.UnstableReactNativeAPI
22
23
  import com.facebook.react.config.ReactFeatureFlags
24
+ import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
23
25
  import com.facebook.react.uimanager.IllegalViewOperationException
26
+ import com.facebook.react.uimanager.JSKeyDispatcher
24
27
  import com.facebook.react.uimanager.JSPointerDispatcher
25
28
  import com.facebook.react.uimanager.JSTouchDispatcher
26
29
  import com.facebook.react.uimanager.common.UIManagerType
@@ -37,6 +40,7 @@ public class ReactSurfaceView(context: Context?, private val surface: ReactSurfa
37
40
  ReactRootView(context) {
38
41
  private val jsTouchDispatcher: JSTouchDispatcher = JSTouchDispatcher(this)
39
42
  private var jsPointerDispatcher: JSPointerDispatcher? = null
43
+ private var jsKeyDispatcher: JSKeyDispatcher? = null
40
44
  private var wasMeasured = false
41
45
  private var widthMeasureSpec = 0
42
46
  private var heightMeasureSpec = 0
@@ -45,6 +49,9 @@ public class ReactSurfaceView(context: Context?, private val surface: ReactSurfa
45
49
  if (ReactFeatureFlags.dispatchPointerEvents) {
46
50
  jsPointerDispatcher = JSPointerDispatcher(this)
47
51
  }
52
+ if (ReactNativeFeatureFlags.enableKeyEvents()) {
53
+ jsKeyDispatcher = JSKeyDispatcher()
54
+ }
48
55
  }
49
56
 
50
57
  override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
@@ -188,6 +195,51 @@ public class ReactSurfaceView(context: Context?, private val surface: ReactSurfa
188
195
  }
189
196
  }
190
197
 
198
+ override fun dispatchJSKeyEvent(event: KeyEvent) {
199
+ if (jsKeyDispatcher == null) {
200
+ if (!ReactNativeFeatureFlags.enableKeyEvents()) {
201
+ return
202
+ }
203
+ FLog.w(TAG, "Unable to dispatch key events to JS before the dispatcher is available")
204
+ return
205
+ }
206
+ val eventDispatcher = surface.eventDispatcher
207
+ if (eventDispatcher != null) {
208
+ jsKeyDispatcher?.handleKeyEvent(event, eventDispatcher, surface.surfaceID)
209
+ } else {
210
+ FLog.w(
211
+ TAG,
212
+ "Unable to dispatch key events to JS as the React instance has not been attached",
213
+ )
214
+ }
215
+ }
216
+
217
+ override fun requestChildFocus(child: View?, focused: View?) {
218
+ super.requestChildFocus(child, focused)
219
+
220
+ if (ReactNativeFeatureFlags.enableKeyEvents()) {
221
+ val focusedViewTag = focused?.id
222
+ if (focusedViewTag != null) {
223
+ jsKeyDispatcher?.setFocusedView(focusedViewTag)
224
+ }
225
+ }
226
+ }
227
+
228
+ override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
229
+ super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
230
+
231
+ if (ReactNativeFeatureFlags.enableKeyEvents()) {
232
+ if (gainFocus) {
233
+ val focusedViewTag = focusedChild?.id
234
+ if (focusedViewTag != null) {
235
+ jsKeyDispatcher?.setFocusedView(focusedViewTag)
236
+ }
237
+ } else {
238
+ jsKeyDispatcher?.clearFocus()
239
+ }
240
+ }
241
+ }
242
+
191
243
  override fun hasActiveReactContext(): Boolean =
192
244
  surface.isAttached && surface.reactHost?.currentReactContext != null
193
245
 
@@ -149,6 +149,9 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
149
149
  // https://android.googlesource.com/platform/frameworks/base/+/a175a5b/core/java/android/view/View.java#2712
150
150
  // `mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | LAYOUT_DIRECTION_INHERIT`
151
151
  // Therefore we set the following options as such:
152
+ if (ReactNativeFeatureFlags.shouldSetIsClickableByDefault()) {
153
+ view.setClickable(true);
154
+ }
152
155
  view.setFocusable(false);
153
156
  view.setFocusableInTouchMode(false);
154
157
 
@@ -678,6 +681,7 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
678
681
  @Override
679
682
  protected void onAfterUpdateTransaction(@NonNull T view) {
680
683
  super.onAfterUpdateTransaction(view);
684
+ configureClickableState(view);
681
685
  updateViewAccessibility(view);
682
686
 
683
687
  Boolean invalidateTransform = (Boolean) view.getTag(R.id.invalidate_transform);
@@ -770,6 +774,16 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
770
774
  MapBuilder.of(
771
775
  "phasedRegistrationNames",
772
776
  MapBuilder.of("bubbled", "onFocus", "captured", "onFocusCapture")))
777
+ .put(
778
+ "topKeyDown",
779
+ MapBuilder.of(
780
+ "phasedRegistrationNames",
781
+ MapBuilder.of("bubbled", "onKeyDown", "captured", "onKeyDownCapture")))
782
+ .put(
783
+ "topKeyUp",
784
+ MapBuilder.of(
785
+ "phasedRegistrationNames",
786
+ MapBuilder.of("bubbled", "onKeyUp", "captured", "onKeyUpCapture")))
773
787
  .build());
774
788
  return eventTypeConstants;
775
789
  }
@@ -1001,6 +1015,25 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
1001
1015
 
1002
1016
  // Please add new props to BaseViewManagerDelegate as well!
1003
1017
 
1018
+ private static <T extends View> void configureClickableState(@NonNull T view) {
1019
+ if (!ReactNativeFeatureFlags.shouldSetIsClickableByDefault()) {
1020
+ return;
1021
+ }
1022
+
1023
+ boolean shouldBeClickable =
1024
+ !(view instanceof ReactPointerEventsView)
1025
+ || PointerEvents.canBeTouchTarget(((ReactPointerEventsView) view).getPointerEvents());
1026
+
1027
+ // NOTE: In Android O+, setClickable(true) has the side effect of setting focusable=true.
1028
+ // We need to preserve the original focusable state to respect the focusable prop.
1029
+ boolean wasFocusable = view.isFocusable();
1030
+ boolean wasFocusableInTouchMode = view.isFocusableInTouchMode();
1031
+
1032
+ view.setClickable(shouldBeClickable);
1033
+ view.setFocusable(wasFocusable);
1034
+ view.setFocusableInTouchMode(wasFocusableInTouchMode);
1035
+ }
1036
+
1004
1037
  /**
1005
1038
  * A helper class to keep track of the original focus change listener if one is set. This is
1006
1039
  * especially helpful for views that are recycled so we can retain and restore the original
@@ -0,0 +1,65 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ package com.facebook.react.uimanager
9
+
10
+ import android.view.KeyEvent as AndroidKeyEvent
11
+ import android.view.View
12
+ import com.facebook.react.uimanager.events.EventDispatcher
13
+ import com.facebook.react.uimanager.events.KeyDownEvent
14
+ import com.facebook.react.uimanager.events.KeyUpEvent
15
+
16
+ /**
17
+ * JSKeyDispatcher handles dispatching keyboard events to JS from RootViews. It sends keydown and
18
+ * keyup events according to the W3C KeyboardEvent specification, supporting both capture and bubble
19
+ * phases.
20
+ *
21
+ * The keydown and keyup events provide a code indicating which key is pressed. The event target is
22
+ * derived from the currently focused Android view.
23
+ */
24
+ internal class JSKeyDispatcher {
25
+ private var focusedViewTag: Int = View.NO_ID
26
+
27
+ fun handleKeyEvent(
28
+ keyEvent: AndroidKeyEvent,
29
+ eventDispatcher: EventDispatcher,
30
+ surfaceId: Int,
31
+ ) {
32
+ if (focusedViewTag == View.NO_ID) {
33
+ return
34
+ }
35
+
36
+ when (keyEvent.action) {
37
+ AndroidKeyEvent.ACTION_DOWN -> {
38
+ eventDispatcher.dispatchEvent(
39
+ KeyDownEvent(
40
+ surfaceId,
41
+ focusedViewTag,
42
+ keyEvent,
43
+ )
44
+ )
45
+ }
46
+ AndroidKeyEvent.ACTION_UP -> {
47
+ eventDispatcher.dispatchEvent(
48
+ KeyUpEvent(
49
+ surfaceId,
50
+ focusedViewTag,
51
+ keyEvent,
52
+ )
53
+ )
54
+ }
55
+ }
56
+ }
57
+
58
+ fun setFocusedView(viewTag: Int) {
59
+ focusedViewTag = viewTag
60
+ }
61
+
62
+ fun clearFocus() {
63
+ focusedViewTag = View.NO_ID
64
+ }
65
+ }
@@ -26,7 +26,6 @@ import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
26
26
  import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
27
27
  import com.facebook.react.common.build.ReactBuildConfig;
28
28
  import com.facebook.react.modules.i18nmanager.I18nUtil;
29
- import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
30
29
  import com.facebook.react.uimanager.events.EventDispatcher;
31
30
  import com.facebook.systrace.Systrace;
32
31
  import com.facebook.systrace.SystraceMessage;
@@ -782,13 +781,6 @@ public class UIImplementation {
782
781
  mViewManagers.invalidate();
783
782
  }
784
783
 
785
- // NOTE: When converted to Kotlin this method should be `internal` due to
786
- // visibility restriction for `NotThreadSafeViewHierarchyUpdateDebugListener`
787
- public void setViewHierarchyUpdateDebugListener(
788
- @Nullable NotThreadSafeViewHierarchyUpdateDebugListener listener) {
789
- mOperationsQueue.setViewHierarchyUpdateDebugListener(listener);
790
- }
791
-
792
784
  protected final void removeShadowNode(ReactShadowNode nodeToRemove) {
793
785
  removeShadowNodeRecursive(nodeToRemove);
794
786
  nodeToRemove.dispose();
@@ -45,7 +45,6 @@ import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
45
45
  import com.facebook.react.common.build.ReactBuildConfig;
46
46
  import com.facebook.react.module.annotations.ReactModule;
47
47
  import com.facebook.react.uimanager.common.ViewUtil;
48
- import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
49
48
  import com.facebook.react.uimanager.events.EventDispatcher;
50
49
  import com.facebook.react.uimanager.events.EventDispatcherImpl;
51
50
  import com.facebook.react.uimanager.events.RCTEventEmitter;
@@ -699,13 +698,6 @@ public class UIManagerModule extends ReactContextBaseJavaModule
699
698
  }
700
699
  }
701
700
 
702
- // NOTE: When converted to Kotlin this method should be `internal` due to
703
- // visibility restriction for `NotThreadSafeViewHierarchyUpdateDebugListener`
704
- public void setViewHierarchyUpdateDebugListener(
705
- @Nullable NotThreadSafeViewHierarchyUpdateDebugListener listener) {
706
- mUIImplementation.setViewHierarchyUpdateDebugListener(listener);
707
- }
708
-
709
701
  @Override
710
702
  public EventDispatcher getEventDispatcher() {
711
703
  return mEventDispatcher;
@@ -29,7 +29,6 @@ import com.facebook.react.common.annotations.internal.LegacyArchitecture;
29
29
  import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel;
30
30
  import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
31
31
  import com.facebook.react.modules.core.ReactChoreographer;
32
- import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
33
32
  import com.facebook.systrace.Systrace;
34
33
  import com.facebook.systrace.SystraceMessage;
35
34
  import com.facebook.yoga.YogaDirection;
@@ -584,7 +583,6 @@ public class UIViewOperationQueue {
584
583
  @GuardedBy("mNonBatchedOperationsLock")
585
584
  private ArrayDeque<UIOperation> mNonBatchedOperations = new ArrayDeque<>();
586
585
 
587
- private @Nullable NotThreadSafeViewHierarchyUpdateDebugListener mViewHierarchyUpdateDebugListener;
588
586
  private boolean mIsDispatchUIFrameCallbackEnqueued = false;
589
587
  private boolean mIsInIllegalUIState = false;
590
588
  private boolean mIsProfilingNextBatch = false;
@@ -619,13 +617,6 @@ public class UIViewOperationQueue {
619
617
  return mNativeViewHierarchyManager;
620
618
  }
621
619
 
622
- // NOTE: When converted to Kotlin this method should be `internal` due to
623
- // visibility restriction for `NotThreadSafeViewHierarchyUpdateDebugListener`
624
- public void setViewHierarchyUpdateDebugListener(
625
- @Nullable NotThreadSafeViewHierarchyUpdateDebugListener listener) {
626
- mViewHierarchyUpdateDebugListener = listener;
627
- }
628
-
629
620
  public void profileNextBatch() {
630
621
  mIsProfilingNextBatch = true;
631
622
  mProfiledBatchCommitStartTime = 0;
@@ -833,10 +824,6 @@ public class UIViewOperationQueue {
833
824
  }
834
825
  }
835
826
 
836
- if (mViewHierarchyUpdateDebugListener != null) {
837
- mViewHierarchyUpdateDebugListener.onViewHierarchyUpdateEnqueued();
838
- }
839
-
840
827
  Runnable runOperations =
841
828
  new Runnable() {
842
829
  @Override
@@ -926,9 +913,6 @@ public class UIViewOperationQueue {
926
913
  // Clear layout animation, as animation only apply to current UI operations batch.
927
914
  mNativeViewHierarchyManager.clearLayoutAnimation();
928
915
 
929
- if (mViewHierarchyUpdateDebugListener != null) {
930
- mViewHierarchyUpdateDebugListener.onViewHierarchyUpdateFinished();
931
- }
932
916
  } catch (Exception e) {
933
917
  mIsInIllegalUIState = true;
934
918
  throw e;
@@ -0,0 +1,23 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ package com.facebook.react.uimanager.events
9
+
10
+ import android.view.KeyEvent as AndroidKeyEvent
11
+
12
+ internal class KeyDownEvent(
13
+ surfaceId: Int,
14
+ viewTag: Int,
15
+ keyEvent: AndroidKeyEvent,
16
+ ) : KeyEvent(surfaceId, viewTag, keyEvent) {
17
+
18
+ override fun getEventName(): String = EVENT_NAME
19
+
20
+ companion object {
21
+ private const val EVENT_NAME: String = "topKeyDown"
22
+ }
23
+ }