Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
private var listeners: CopyOnWriteArrayList<TextWatcher>?

public var stagedInputType: Int
internal var stagedAutoCapitalize: Int = UNSET_AUTO_CAPITALIZE
public var submitBehavior: String? = null
public var dragAndDropFilter: List<String>? = null

Expand Down Expand Up @@ -1222,6 +1223,7 @@ public open class ReactEditText public constructor(context: Context) : AppCompat

public companion object {
public val DEBUG_MODE: Boolean = ReactBuildConfig.DEBUG && false
internal const val UNSET_AUTO_CAPITALIZE: Int = -1

private val keyListener: KeyListener = QwertyKeyListener.getInstanceForFullKeyboard()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,9 @@ public open class ReactTextInputManager public constructor() :
}
}

updateStagedInputTypeFlag(view, AUTOCAPITALIZE_FLAGS, autoCapitalizeValue)
// Deferred to onAfterUpdateTransaction() so we can reconcile with the resolved
// keyboard type — AUTOCAPITALIZE_FLAGS collides with numeric inputType flags.
view.stagedAutoCapitalize = autoCapitalizeValue
}

@ReactProp(name = "keyboardType")
Expand Down Expand Up @@ -882,6 +884,7 @@ public open class ReactTextInputManager public constructor() :
override fun onAfterUpdateTransaction(view: ReactEditText) {
super.onAfterUpdateTransaction(view)
view.maybeUpdateTypeface()
reconcileAutoCapitalize(view)
view.commitStagedInputType()
}

Expand Down Expand Up @@ -1129,6 +1132,25 @@ public open class ReactTextInputManager public constructor() :

private const val IME_ACTION_ID = 0x670

// AUTOCAPITALIZE_FLAGS (0x7000) shares bit positions with TYPE_NUMBER_FLAG_SIGNED
// (0x1000) and TYPE_NUMBER_FLAG_DECIMAL (0x2000). We apply autocapitalize here
// after all props are set so the resolved input class determines whether the
// flags are meaningful.
private fun reconcileAutoCapitalize(view: ReactEditText) {
val autoCapValue = view.stagedAutoCapitalize
if (autoCapValue == ReactEditText.UNSET_AUTO_CAPITALIZE) return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also bail if there will be no change?


val inputClass = view.stagedInputType and InputType.TYPE_MASK_CLASS
if (inputClass == InputType.TYPE_CLASS_TEXT) {
updateStagedInputTypeFlag(view, AUTOCAPITALIZE_FLAGS, autoCapValue)
} else {
// Only strip 0x4000 (CAP_SENTENCES) — 0x1000/0x2000 are valid numeric flags
// (SIGNED/DECIMAL) and must not be cleared.
view.stagedInputType =
view.stagedInputType and InputType.TYPE_TEXT_FLAG_CAP_SENTENCES.inv()
}
}

// Sets the correct password type, since numeric and text passwords have different types
private fun checkPasswordType(view: ReactEditText) {
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,65 @@ class ReactTextInputPropertyTest {
assertThat(view.inputType and InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isZero
}

@Test
fun testAutoCapitalizeDoesNotStripNumericFlags() {
val numericTypeFlags =
(InputType.TYPE_CLASS_NUMBER or
InputType.TYPE_NUMBER_FLAG_DECIMAL or
InputType.TYPE_NUMBER_FLAG_SIGNED)

manager.updateProperties(view, buildStyles("keyboardType", "numeric"))
assertThat(view.inputType and numericTypeFlags).isEqualTo(numericTypeFlags)

manager.updateProperties(
view,
buildStyles("autoCapitalize", InputType.TYPE_TEXT_FLAG_CAP_SENTENCES),
)
assertThat(view.inputType and InputType.TYPE_NUMBER_FLAG_SIGNED).isNotZero
assertThat(view.inputType and InputType.TYPE_NUMBER_FLAG_DECIMAL).isNotZero
}

@Test
fun testAutoCapitalizeAndNumericKeyboardInSameTransaction() {
val numericTypeFlags =
(InputType.TYPE_CLASS_NUMBER or
InputType.TYPE_NUMBER_FLAG_DECIMAL or
InputType.TYPE_NUMBER_FLAG_SIGNED)

manager.updateProperties(
view,
buildStyles(
"autoCapitalize",
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES,
"keyboardType",
"numeric",
),
)
assertThat(view.inputType and numericTypeFlags).isEqualTo(numericTypeFlags)
assertThat(view.inputType and InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isZero
}

@Test
fun testAutoCapitalizeReappliesWhenKeyboardTypeChangesFromNumericToText() {
// CAP_SENTENCES (0x4000) doesn't share a bit position with any numeric flag,
// unlike CAP_WORDS (0x2000) / CAP_CHARACTERS (0x1000).
manager.updateProperties(
view,
buildStyles(
"autoCapitalize",
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES,
"keyboardType",
"numeric",
),
)
assertThat(view.inputType and InputType.TYPE_MASK_CLASS).isEqualTo(InputType.TYPE_CLASS_NUMBER)
assertThat(view.inputType and InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isZero

manager.updateProperties(view, buildStyles("keyboardType", "default"))
assertThat(view.inputType and InputType.TYPE_MASK_CLASS).isEqualTo(InputType.TYPE_CLASS_TEXT)
assertThat(view.inputType and InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isNotZero
}

@Test
fun testPlaceholder() {
manager.updateProperties(view, buildStyles())
Expand Down