From eb81d1e355cf3a9ef50781fbc4f07682b0ebbae5 Mon Sep 17 00:00:00 2001 From: Nikhil Pakhloo Date: Wed, 8 Jul 2026 15:34:52 +0530 Subject: [PATCH 1/2] fix(android): show soft keyboard on text selection --- .../react/views/textinput/ReactEditText.kt | 17 +++++++++++++++ .../textinput/ReactTextInputPropertyTest.kt | 21 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt index 0415dca1126b..9f023587c000 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt @@ -130,6 +130,7 @@ public open class ReactEditText public constructor(context: Context) : AppCompat private var keyListener: InternalKeyListener? = null private var detectScrollMovement = false private var onKeyPress = false + private var selectionWasCollapsed = true private val textAttributes: TextAttributes private var typefaceDirty = false private var fontFamily: String? = null @@ -492,6 +493,7 @@ public open class ReactEditText public constructor(context: Context) : AppCompat if (selectionWatcher != null && hasFocus()) { selectionWatcher?.onSelectionChanged(selStart, selEnd) } + maybeShowSoftKeyboardForSelection(selStart, selEnd) } override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) { @@ -499,6 +501,21 @@ public open class ReactEditText public constructor(context: Context) : AppCompat if (focused && selectionWatcher != null) { selectionWatcher?.onSelectionChanged(selectionStart, selectionEnd) } + if (focused) { + maybeShowSoftKeyboardForSelection(selectionStart, selectionEnd) + } + } + + private fun maybeShowSoftKeyboardForSelection(selectionStart: Int, selectionEnd: Int) { + if (!hasFocus() || !showSoftInputOnFocus) { + return + } + + val selectionIsCollapsed = selectionStart == selectionEnd + if (!selectionIsCollapsed && selectionWasCollapsed) { + showSoftKeyboard() + } + selectionWasCollapsed = selectionIsCollapsed } internal fun setSelectionWatcher(selectionWatcher: SelectionWatcher?) { diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt index d99a2c8be1cd..710314fc902d 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt @@ -11,6 +11,7 @@ package com.facebook.react.views.textinput +import android.content.Context import android.graphics.Color import android.os.Build import android.text.InputFilter @@ -46,6 +47,15 @@ import org.robolectric.RuntimeEnvironment @RunWith(RobolectricTestRunner::class) class ReactTextInputPropertyTest { + private class TestReactEditText(context: Context) : ReactEditText(context) { + var showSoftKeyboardCallCount = 0 + + override fun showSoftKeyboard(): Boolean { + showSoftKeyboardCallCount++ + return true + } + } + private lateinit var context: BridgeReactContext private lateinit var catalystInstanceMock: CatalystInstance private lateinit var themedContext: ThemedReactContext @@ -74,6 +84,17 @@ class ReactTextInputPropertyTest { view = manager.createViewInstance(themedContext) } + @Test + fun testShowsSoftKeyboardWhenSelectionStartsWhileFocused() { + val textInput = TestReactEditText(themedContext) + textInput.setText("hello") + textInput.onFocusChanged(true, View.FOCUS_DOWN, null) + + textInput.setSelection(1, 3) + + assertThat(textInput.showSoftKeyboardCallCount).isEqualTo(1) + } + @Test fun testAutoCorrect() { manager.updateProperties(view, buildStyles()) From 321dfba3c742f2f848e8f11fea1b4fa1c80c86bd Mon Sep 17 00:00:00 2001 From: Nikhil Pakhloo Date: Wed, 8 Jul 2026 15:58:57 +0530 Subject: [PATCH 2/2] chore: format fantom docs --- private/react-native-fantom/__docs__/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/private/react-native-fantom/__docs__/README.md b/private/react-native-fantom/__docs__/README.md index d5997c130e8d..dbfb007c8c1b 100644 --- a/private/react-native-fantom/__docs__/README.md +++ b/private/react-native-fantom/__docs__/README.md @@ -187,12 +187,12 @@ hi underlying native (Fabric/TurboModules) code, so tests stay close to real usage and are more resilient to internal refactors. Observe results through the public surface too — e.g. assert the rendered output - (`root.getRenderedOutput(...)`) or values delivered to public listeners - rather than reading private state. + (`root.getRenderedOutput(...)`) or values delivered to public listeners rather + than reading private state. - When Fantom doesn't support something (a native module, a capability, a way to observe a result, etc.), it's fine to reach into internals to work around - that limitation. Prefer a short comment explaining why the internal access is - necessary. + that limitation. Prefer a short comment explaining why the internal access + is necessary. - Place test files in `__tests__` directories alongside the code being tested. - Benchmark tests use the `-benchmark-itest.js` suffix. - Use `Fantom.runTask()` to render and run synchronous operations; it ensures