diff --git a/FabricExample/src/screens/Examples/Events/index.tsx b/FabricExample/src/screens/Examples/Events/index.tsx
index 00c679fb66..a7d4bbc283 100644
--- a/FabricExample/src/screens/Examples/Events/index.tsx
+++ b/FabricExample/src/screens/Examples/Events/index.tsx
@@ -24,7 +24,7 @@ function EventsListener() {
Toast.show({
type: "info",
text1: "⬆️ ⌨️ Keyboard will show",
- text2: `📲 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms`,
+ text2: `📲 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms, type: ${e.type}`,
});
});
const shown = KeyboardEvents.addListener("keyboardDidShow", (e) => {
@@ -33,7 +33,7 @@ function EventsListener() {
Toast.show({
type: "success",
text1: "⌨️ Keyboard is shown",
- text2: `👋 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms`,
+ text2: `👋 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms, type: ${e.type}`,
});
});
const hide = KeyboardEvents.addListener("keyboardWillHide", (e) => {
@@ -42,7 +42,7 @@ function EventsListener() {
Toast.show({
type: "info",
text1: "⬇️ ⌨️ Keyboard will hide",
- text2: `📲 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms`,
+ text2: `📲 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms, type: ${e.type}`,
});
});
const hid = KeyboardEvents.addListener("keyboardDidHide", (e) => {
@@ -51,7 +51,7 @@ function EventsListener() {
Toast.show({
type: "error",
text1: "⌨️ Keyboard is hidden",
- text2: `🤐 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms`,
+ text2: `🤐 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms, type: ${e.type}`,
});
});
@@ -63,7 +63,7 @@ function EventsListener() {
};
}, []);
- return ;
+ return ;
}
export default function Events() {
diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt
index f2dd54bd7e..5045eaec76 100644
--- a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt
+++ b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt
@@ -2,6 +2,7 @@ package com.reactnativekeyboardcontroller.extensions
import android.os.Build
import android.text.Editable
+import android.text.InputType
import android.text.TextWatcher
import android.view.View
import android.widget.EditText
@@ -110,6 +111,40 @@ fun EditText?.focus() {
}
}
+val EditText?.keyboardType: String
+ get() {
+ if (this == null) {
+ return "default"
+ }
+
+ // Extract base input type class
+ val inputTypeClass = inputType and InputType.TYPE_MASK_CLASS
+ val inputTypeVariation = inputType and InputType.TYPE_MASK_VARIATION
+
+ // Check for special input types
+ return when {
+ inputTypeVariation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS -> "email-address"
+ inputTypeVariation == InputType.TYPE_TEXT_VARIATION_URI -> "url"
+ inputTypeVariation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD -> "visible-password"
+
+ // Check for specific input type classes
+ inputTypeClass == InputType.TYPE_CLASS_NUMBER ->
+ when {
+ (inputType and InputType.TYPE_NUMBER_FLAG_DECIMAL) != 0 &&
+ (inputType and InputType.TYPE_NUMBER_FLAG_SIGNED) == 0 -> "decimal-pad"
+
+ (inputType and InputType.TYPE_NUMBER_FLAG_SIGNED) != 0 -> "numeric"
+
+ else -> "number-pad"
+ }
+
+ inputTypeClass == InputType.TYPE_CLASS_PHONE -> "phone-pad"
+ inputTypeClass == InputType.TYPE_CLASS_TEXT -> "default"
+
+ else -> "default"
+ }
+ }
+
class KeyboardControllerSelectionWatcher(
private val editText: ReactEditText,
private val action: (start: Int, end: Int, startX: Double, startY: Double, endX: Double, endY: Double) -> Unit,
diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt b/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt
index 191591025d..2a06f8d6c0 100644
--- a/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt
+++ b/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt
@@ -19,8 +19,10 @@ import com.reactnativekeyboardcontroller.extensions.dispatchEvent
import com.reactnativekeyboardcontroller.extensions.dp
import com.reactnativekeyboardcontroller.extensions.emitEvent
import com.reactnativekeyboardcontroller.extensions.isKeyboardAnimation
+import com.reactnativekeyboardcontroller.extensions.keyboardType
import com.reactnativekeyboardcontroller.interactive.InteractiveKeyboardProvider
import com.reactnativekeyboardcontroller.log.Logger
+import com.reactnativekeyboardcontroller.traversal.FocusedInputHolder
import kotlin.math.abs
private val TAG = KeyboardAnimationCallback::class.qualifiedName
@@ -425,6 +427,7 @@ class KeyboardAnimationCallback(
params.putInt("duration", duration)
params.putDouble("timestamp", System.currentTimeMillis().toDouble())
params.putInt("target", viewTagFocused)
+ params.putString("type", FocusedInputHolder.get()?.keyboardType)
return params
}
diff --git a/docs/docs/api/keyboard-events.md b/docs/docs/api/keyboard-events.md
index 9920b5f0dd..c6e550c17c 100644
--- a/docs/docs/api/keyboard-events.md
+++ b/docs/docs/api/keyboard-events.md
@@ -16,10 +16,10 @@ keywords:
This library exposes 4 events which are available on all platforms:
-- keyboardWillShow
-- keyboardWillHide
-- keyboardDidShow
-- keyboardDidHide
+- `keyboardWillShow` - emitted when the keyboard is about to appear.
+- `keyboardWillHide` - emitted when the keyboard is about to disappear.
+- `keyboardDidShow` - emitted when the keyboard has completed its animation and is fully visible on the screen.
+- `keyboardDidHide` - emitted when the keyboard has completed its animation and is fully hidden.
## Event structure
@@ -31,6 +31,7 @@ type KeyboardEventData = {
duration: number; // duration of the animation
timestamp: number; // timestamp of the event from native thread
target: number; // tag of the focused TextInput
+ type: string; // `keyboardType` property from focused `TextInput`
};
```
diff --git a/example/src/screens/Examples/Events/index.tsx b/example/src/screens/Examples/Events/index.tsx
index 00c679fb66..a7d4bbc283 100644
--- a/example/src/screens/Examples/Events/index.tsx
+++ b/example/src/screens/Examples/Events/index.tsx
@@ -24,7 +24,7 @@ function EventsListener() {
Toast.show({
type: "info",
text1: "⬆️ ⌨️ Keyboard will show",
- text2: `📲 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms`,
+ text2: `📲 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms, type: ${e.type}`,
});
});
const shown = KeyboardEvents.addListener("keyboardDidShow", (e) => {
@@ -33,7 +33,7 @@ function EventsListener() {
Toast.show({
type: "success",
text1: "⌨️ Keyboard is shown",
- text2: `👋 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms`,
+ text2: `👋 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms, type: ${e.type}`,
});
});
const hide = KeyboardEvents.addListener("keyboardWillHide", (e) => {
@@ -42,7 +42,7 @@ function EventsListener() {
Toast.show({
type: "info",
text1: "⬇️ ⌨️ Keyboard will hide",
- text2: `📲 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms`,
+ text2: `📲 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms, type: ${e.type}`,
});
});
const hid = KeyboardEvents.addListener("keyboardDidHide", (e) => {
@@ -51,7 +51,7 @@ function EventsListener() {
Toast.show({
type: "error",
text1: "⌨️ Keyboard is hidden",
- text2: `🤐 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms`,
+ text2: `🤐 Height: ${e.height}, duration: ${e.duration}ms, delay: ${delay}ms, type: ${e.type}`,
});
});
@@ -63,7 +63,7 @@ function EventsListener() {
};
}, []);
- return ;
+ return ;
}
export default function Events() {
diff --git a/ios/events/KeyboardEventEmitterPayload.swift b/ios/events/KeyboardEventEmitterPayload.swift
new file mode 100644
index 0000000000..f4777d6bea
--- /dev/null
+++ b/ios/events/KeyboardEventEmitterPayload.swift
@@ -0,0 +1,22 @@
+//
+// KeyboardEventEmitterPayload.swift
+// Pods
+//
+// Created by Kiryl Ziusko on 07/12/2024.
+//
+
+import Foundation
+import UIKit
+
+public func buildEventParams(_ height: Double, _ duration: Int, _ tag: NSNumber) -> [AnyHashable: Any] {
+ var data = [AnyHashable: Any]()
+ let input = FocusedInputHolder.shared.get()
+
+ data["height"] = height
+ data["duration"] = duration
+ data["timestamp"] = Date.currentTimeStamp
+ data["target"] = tag
+ data["type"] = input?.keyboardType.name ?? "default"
+
+ return data
+}
diff --git a/ios/extensions/UIKeyboardType.swift b/ios/extensions/UIKeyboardType.swift
new file mode 100644
index 0000000000..65715f6147
--- /dev/null
+++ b/ios/extensions/UIKeyboardType.swift
@@ -0,0 +1,30 @@
+//
+// UIKeyboardType.swift
+// Pods
+//
+// Created by Kiryl Ziusko on 08/12/2024.
+//
+
+import Foundation
+import UIKit
+
+extension UIKeyboardType {
+ private static let keyboardTypeToStringMapping: [UIKeyboardType: String] = [
+ .default: "default",
+ .asciiCapable: "ascii-capable",
+ .numbersAndPunctuation: "numbers-and-punctuation",
+ .URL: "url",
+ .numberPad: "number-pad",
+ .phonePad: "phone-pad",
+ .namePhonePad: "name-phone-pad",
+ .emailAddress: "email-address",
+ .decimalPad: "decimal-pad",
+ .twitter: "twitter",
+ .webSearch: "web-search",
+ .asciiCapableNumberPad: "ascii-capable-number-pad",
+ ]
+
+ var name: String {
+ return UIKeyboardType.keyboardTypeToStringMapping[self] ?? "default"
+ }
+}
diff --git a/ios/observers/KeyboardMovementObserver.swift b/ios/observers/KeyboardMovementObserver.swift
index 68871b15a5..d281499d09 100644
--- a/ios/observers/KeyboardMovementObserver.swift
+++ b/ios/observers/KeyboardMovementObserver.swift
@@ -173,7 +173,7 @@ public class KeyboardMovementObserver: NSObject {
onRequestAnimation()
onEvent("onKeyboardMoveStart", Float(keyboardHeight) as NSNumber, 1, duration as NSNumber, tag)
- onNotify("KeyboardController::keyboardWillShow", getEventParams(keyboardHeight, duration))
+ onNotify("KeyboardController::keyboardWillShow", buildEventParams(keyboardHeight, duration, tag))
setupKeyboardWatcher()
initializeAnimation(fromValue: prevKeyboardPosition, toValue: keyboardHeight)
@@ -187,7 +187,7 @@ public class KeyboardMovementObserver: NSObject {
onRequestAnimation()
onEvent("onKeyboardMoveStart", 0, 0, duration as NSNumber, tag)
- onNotify("KeyboardController::keyboardWillHide", getEventParams(0, duration))
+ onNotify("KeyboardController::keyboardWillHide", buildEventParams(0, duration, tag))
setupKeyboardWatcher()
removeKVObserver()
@@ -210,7 +210,7 @@ public class KeyboardMovementObserver: NSObject {
onCancelAnimation()
onEvent("onKeyboardMoveEnd", height as NSNumber, progress as NSNumber, duration as NSNumber, tag)
- onNotify("KeyboardController::keyboardDidShow", getEventParams(height, duration))
+ onNotify("KeyboardController::keyboardDidShow", buildEventParams(height, duration, tag))
removeKeyboardWatcher()
setupKVObserver()
@@ -224,7 +224,7 @@ public class KeyboardMovementObserver: NSObject {
onCancelAnimation()
onEvent("onKeyboardMoveEnd", 0 as NSNumber, 0, duration as NSNumber, tag)
- onNotify("KeyboardController::keyboardDidHide", getEventParams(0, duration))
+ onNotify("KeyboardController::keyboardDidHide", buildEventParams(0, duration, tag))
removeKeyboardWatcher()
animation = nil
@@ -309,14 +309,4 @@ public class KeyboardMovementObserver: NSObject {
tag
)
}
-
- private func getEventParams(_ height: Double, _ duration: Int) -> [AnyHashable: Any] {
- var data = [AnyHashable: Any]()
- data["height"] = height
- data["duration"] = duration
- data["timestamp"] = Date.currentTimeStamp
- data["target"] = tag
-
- return data
- }
}
diff --git a/ios/protocols/TextInput.swift b/ios/protocols/TextInput.swift
index deb1458453..f24c9ca6ae 100644
--- a/ios/protocols/TextInput.swift
+++ b/ios/protocols/TextInput.swift
@@ -10,6 +10,7 @@ import Foundation
import UIKit
public protocol TextInput: AnyObject {
+ var keyboardType: UIKeyboardType { get }
func focus()
}
diff --git a/src/types.ts b/src/types.ts
index b2801519cf..5dca359ad1 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -2,6 +2,7 @@ import type { PropsWithChildren } from "react";
import type {
EmitterSubscription,
NativeSyntheticEvent,
+ TextInputProps,
ViewProps,
} from "react-native";
@@ -146,6 +147,7 @@ export type KeyboardEventData = {
duration: number;
timestamp: number;
target: number;
+ type: TextInputProps["keyboardType"];
};
export type KeyboardEventsModule = {
addListener: (