react-native-keyboard-controller 1.17.4 → 1.18.0

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 (185) hide show
  1. package/README.md +4 -1
  2. package/android/src/base/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +6 -5
  3. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardBackgroundViewManager.kt +19 -0
  4. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +4 -0
  5. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +3 -5
  6. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +3 -5
  7. package/android/src/fabric/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt +3 -5
  8. package/android/src/fabric/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +3 -1
  9. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/Context.kt +20 -0
  10. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt +2 -12
  11. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardBackgroundViewManagerImpl.kt +13 -0
  12. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +2 -6
  13. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardGestureAreaViewManagerImpl.kt +1 -5
  14. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/OverKeyboardViewManagerImpl.kt +1 -5
  15. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +4 -0
  16. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/{StatusBarManagerCompatModuleImpl.kt → statusbar/StatusBarManagerCompatModuleImpl.kt} +31 -5
  17. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/statusbar/StatusBarModuleProxy.kt +86 -0
  18. package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +9 -11
  19. package/android/src/main/java/com/reactnativekeyboardcontroller/views/background/KeyboardBackgroundViewGroup.kt +35 -0
  20. package/android/src/main/java/com/reactnativekeyboardcontroller/views/background/Skins.kt +91 -0
  21. package/android/src/main/jni/reactnativekeyboardcontroller.h +1 -0
  22. package/android/src/main/res/values/attrs.xml +7 -0
  23. package/android/src/main/res/values/colors.xml +35 -0
  24. package/android/src/main/res/values-v29/colors.xml +5 -0
  25. package/android/src/main/res/values-v30/colors.xml +17 -0
  26. package/android/src/main/res/values-v33/colors.xml +16 -0
  27. package/android/src/main/res/values-v34/colors.xml +18 -0
  28. package/android/src/main/res/values-v35/colors.xml +10 -0
  29. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardBackgroundViewManager.kt +15 -0
  30. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +5 -0
  31. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +2 -5
  32. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +2 -5
  33. package/android/src/paper/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt +2 -5
  34. package/android/src/paper/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +3 -1
  35. package/android/src/turbo/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +5 -5
  36. package/common/cpp/react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardBackgroundViewComponentDescriptor.h +27 -0
  37. package/common/cpp/react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardBackgroundViewShadowNode.cpp +14 -0
  38. package/common/cpp/react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardBackgroundViewShadowNode.h +30 -0
  39. package/common/cpp/react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardBackgroundViewState.h +28 -0
  40. package/common/cpp/react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardExtenderComponentDescriptor.h +27 -0
  41. package/common/cpp/react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardExtenderShadowNode.cpp +14 -0
  42. package/common/cpp/react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardExtenderShadowNode.h +30 -0
  43. package/common/cpp/react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardExtenderState.h +28 -0
  44. package/ios/KeyboardControllerModule.mm +9 -0
  45. package/ios/delegates/KCTextInputCompositeDelegate.swift +5 -5
  46. package/ios/events/KeyboardEventEmitterPayload.swift +1 -1
  47. package/ios/extensions/String.swift +12 -0
  48. package/ios/extensions/UIResponder.swift +27 -0
  49. package/ios/interactive/KeyboardAreaExtender.swift +5 -5
  50. package/ios/observers/FocusedInputObserver.swift +14 -5
  51. package/ios/observers/KeyboardMovementObserver.swift +24 -9
  52. package/ios/protocols/TextInput.swift +22 -0
  53. package/ios/swizzling/UIResponderSwizzle.swift +3 -0
  54. package/ios/traversal/KeyboardView.swift +6 -3
  55. package/ios/views/KeyboardBackgroundViewManager.h +29 -0
  56. package/ios/views/KeyboardBackgroundViewManager.mm +168 -0
  57. package/ios/views/KeyboardExtenderContainerView.swift +59 -0
  58. package/ios/views/KeyboardExtenderManager.h +29 -0
  59. package/ios/views/KeyboardExtenderManager.mm +287 -0
  60. package/jest/index.js +6 -1
  61. package/lib/commonjs/animated.js +7 -10
  62. package/lib/commonjs/animated.js.map +1 -1
  63. package/lib/commonjs/bindings.js +15 -1
  64. package/lib/commonjs/bindings.js.map +1 -1
  65. package/lib/commonjs/bindings.native.js +5 -1
  66. package/lib/commonjs/bindings.native.js.map +1 -1
  67. package/lib/commonjs/components/KeyboardAwareScrollView/index.js +49 -29
  68. package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
  69. package/lib/commonjs/components/KeyboardToolbar/Arrow.js +2 -3
  70. package/lib/commonjs/components/KeyboardToolbar/Arrow.js.map +1 -1
  71. package/lib/commonjs/components/KeyboardToolbar/Button.js +2 -3
  72. package/lib/commonjs/components/KeyboardToolbar/Button.js.map +1 -1
  73. package/lib/commonjs/components/KeyboardToolbar/constants.js +17 -0
  74. package/lib/commonjs/components/KeyboardToolbar/constants.js.map +1 -0
  75. package/lib/commonjs/components/KeyboardToolbar/index.js +25 -22
  76. package/lib/commonjs/components/KeyboardToolbar/index.js.map +1 -1
  77. package/lib/commonjs/hooks/useKeyboardState/index.js +18 -8
  78. package/lib/commonjs/hooks/useKeyboardState/index.js.map +1 -1
  79. package/lib/commonjs/index.js +8 -1
  80. package/lib/commonjs/index.js.map +1 -1
  81. package/lib/commonjs/module.js +2 -1
  82. package/lib/commonjs/module.js.map +1 -1
  83. package/lib/commonjs/specs/KeyboardBackgroundViewNativeComponent.js +12 -0
  84. package/lib/commonjs/specs/KeyboardBackgroundViewNativeComponent.js.map +1 -0
  85. package/lib/commonjs/specs/KeyboardExtenderNativeComponent.js +13 -0
  86. package/lib/commonjs/specs/KeyboardExtenderNativeComponent.js.map +1 -0
  87. package/lib/commonjs/specs/NativeKeyboardController.js.map +1 -1
  88. package/lib/commonjs/types/module.js.map +1 -1
  89. package/lib/commonjs/types/views.js.map +1 -1
  90. package/lib/commonjs/views/KeyboardExtender/index.ios.js +43 -0
  91. package/lib/commonjs/views/KeyboardExtender/index.ios.js.map +1 -0
  92. package/lib/commonjs/views/KeyboardExtender/index.js +46 -0
  93. package/lib/commonjs/views/KeyboardExtender/index.js.map +1 -0
  94. package/lib/commonjs/views/index.js +7 -0
  95. package/lib/commonjs/views/index.js.map +1 -1
  96. package/lib/module/animated.js +8 -11
  97. package/lib/module/animated.js.map +1 -1
  98. package/lib/module/bindings.js +14 -0
  99. package/lib/module/bindings.js.map +1 -1
  100. package/lib/module/bindings.native.js +4 -0
  101. package/lib/module/bindings.native.js.map +1 -1
  102. package/lib/module/components/KeyboardAwareScrollView/index.js +50 -30
  103. package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
  104. package/lib/module/components/KeyboardToolbar/Arrow.js +2 -2
  105. package/lib/module/components/KeyboardToolbar/Arrow.js.map +1 -1
  106. package/lib/module/components/KeyboardToolbar/Button.js +2 -2
  107. package/lib/module/components/KeyboardToolbar/Button.js.map +1 -1
  108. package/lib/module/components/KeyboardToolbar/constants.js +11 -0
  109. package/lib/module/components/KeyboardToolbar/constants.js.map +1 -0
  110. package/lib/module/components/KeyboardToolbar/index.js +17 -14
  111. package/lib/module/components/KeyboardToolbar/index.js.map +1 -1
  112. package/lib/module/hooks/useKeyboardState/index.js +18 -6
  113. package/lib/module/hooks/useKeyboardState/index.js.map +1 -1
  114. package/lib/module/index.js +1 -1
  115. package/lib/module/index.js.map +1 -1
  116. package/lib/module/module.js +2 -1
  117. package/lib/module/module.js.map +1 -1
  118. package/lib/module/specs/KeyboardBackgroundViewNativeComponent.js +5 -0
  119. package/lib/module/specs/KeyboardBackgroundViewNativeComponent.js.map +1 -0
  120. package/lib/module/specs/KeyboardExtenderNativeComponent.js +6 -0
  121. package/lib/module/specs/KeyboardExtenderNativeComponent.js.map +1 -0
  122. package/lib/module/specs/NativeKeyboardController.js.map +1 -1
  123. package/lib/module/types/module.js.map +1 -1
  124. package/lib/module/types/views.js.map +1 -1
  125. package/lib/module/views/KeyboardExtender/index.ios.js +36 -0
  126. package/lib/module/views/KeyboardExtender/index.ios.js.map +1 -0
  127. package/lib/module/views/KeyboardExtender/index.js +39 -0
  128. package/lib/module/views/KeyboardExtender/index.js.map +1 -0
  129. package/lib/module/views/index.js +1 -0
  130. package/lib/module/views/index.js.map +1 -1
  131. package/lib/typescript/animated.d.ts +7 -0
  132. package/lib/typescript/bindings.d.ts +14 -1
  133. package/lib/typescript/bindings.native.d.ts +3 -1
  134. package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +2 -2
  135. package/lib/typescript/components/KeyboardToolbar/constants.d.ts +10 -0
  136. package/lib/typescript/hooks/useKeyboardState/index.d.ts +8 -2
  137. package/lib/typescript/index.d.ts +1 -1
  138. package/lib/typescript/specs/KeyboardBackgroundViewNativeComponent.d.ts +6 -0
  139. package/lib/typescript/specs/KeyboardExtenderNativeComponent.d.ts +7 -0
  140. package/lib/typescript/specs/NativeKeyboardController.d.ts +1 -0
  141. package/lib/typescript/types/module.d.ts +15 -3
  142. package/lib/typescript/types/views.d.ts +5 -0
  143. package/lib/typescript/views/KeyboardExtender/index.d.ts +19 -0
  144. package/lib/typescript/views/KeyboardExtender/index.ios.d.ts +19 -0
  145. package/lib/typescript/views/index.d.ts +1 -0
  146. package/package.json +7 -3
  147. package/react-native.config.js +1 -0
  148. package/src/animated.tsx +14 -9
  149. package/src/bindings.native.ts +8 -0
  150. package/src/bindings.ts +18 -0
  151. package/src/components/KeyboardAwareScrollView/index.tsx +72 -47
  152. package/src/components/KeyboardToolbar/Arrow.tsx +2 -2
  153. package/src/components/KeyboardToolbar/Button.tsx +2 -2
  154. package/src/components/KeyboardToolbar/constants.ts +15 -0
  155. package/src/components/KeyboardToolbar/index.tsx +45 -17
  156. package/src/hooks/useKeyboardState/index.ts +25 -6
  157. package/src/index.ts +1 -1
  158. package/src/module.ts +2 -1
  159. package/src/specs/KeyboardBackgroundViewNativeComponent.ts +10 -0
  160. package/src/specs/KeyboardExtenderNativeComponent.ts +13 -0
  161. package/src/specs/NativeKeyboardController.ts +1 -0
  162. package/src/types/module.ts +17 -3
  163. package/src/types/views.ts +5 -0
  164. package/src/views/KeyboardExtender/index.ios.tsx +35 -0
  165. package/src/views/KeyboardExtender/index.tsx +42 -0
  166. package/src/views/index.ts +1 -0
  167. package/ios/extensions/UIKeyboardAppearance.swift +0 -21
  168. package/lib/commonjs/components/hooks/useColorScheme.js +0 -10
  169. package/lib/commonjs/components/hooks/useColorScheme.js.map +0 -1
  170. package/lib/commonjs/monkey-patch.android.js +0 -53
  171. package/lib/commonjs/monkey-patch.android.js.map +0 -1
  172. package/lib/commonjs/monkey-patch.js +0 -11
  173. package/lib/commonjs/monkey-patch.js.map +0 -1
  174. package/lib/module/components/hooks/useColorScheme.js +0 -4
  175. package/lib/module/components/hooks/useColorScheme.js.map +0 -1
  176. package/lib/module/monkey-patch.android.js +0 -42
  177. package/lib/module/monkey-patch.android.js.map +0 -1
  178. package/lib/module/monkey-patch.js +0 -5
  179. package/lib/module/monkey-patch.js.map +0 -1
  180. package/lib/typescript/components/hooks/useColorScheme.d.ts +0 -2
  181. package/lib/typescript/monkey-patch.android.d.ts +0 -2
  182. package/lib/typescript/monkey-patch.d.ts +0 -2
  183. package/src/components/hooks/useColorScheme.ts +0 -5
  184. package/src/monkey-patch.android.ts +0 -41
  185. package/src/monkey-patch.ts +0 -5
package/README.md CHANGED
@@ -10,12 +10,15 @@ A universal keyboard handling solution for React Native — lightweight, fully c
10
10
 
11
11
  - 🧬 Map keyboard movement to animated values
12
12
  - 🧪 `keyboardWillShow` / `keyboardWillHide` events now available on Android
13
- - Change soft input mode on Android
13
+ - 🔮 Change soft input mode on Android
14
+ - ⚡ Preload keyboard to avoid first-time focus lag
14
15
  - 🚀 Reanimated support
15
16
  - 📱 Interactive keyboard dismissing 👆📱
16
17
  - 📚 Prebuilt components (`KeyboardStickyView`, `KeyboardAwareScrollView`, reworked `KeyboardAvoidingView`)
17
18
  - 📐 `KeyboardToolbar` with customizable _**previous**_, _**next**_, and _**done**_ buttons
18
19
  - 🌐 Display anything over the keyboard (without dismissing it) using `OverKeyboardView`
20
+ - 🎨 Match keyboard background with `KeyboardBackgroundView`
21
+ - 🧩 Extend keyboard with custom buttons/UI via `KeyboardExtender`
19
22
  - 📝 Easy retrieval of focused input info
20
23
  - 🧭 Compatible with any navigation library
21
24
  - ✨ More coming soon... stay tuned! 😊
@@ -7,7 +7,7 @@ import com.facebook.react.module.model.ReactModuleInfo
7
7
  import com.facebook.react.module.model.ReactModuleInfoProvider
8
8
  import com.facebook.react.uimanager.ViewManager
9
9
  import com.reactnativekeyboardcontroller.modules.KeyboardControllerModuleImpl
10
- import com.reactnativekeyboardcontroller.modules.StatusBarManagerCompatModuleImpl
10
+ import com.reactnativekeyboardcontroller.modules.statusbar.StatusBarManagerCompatModuleImpl
11
11
 
12
12
  class KeyboardControllerPackage : BaseReactPackage() {
13
13
  override fun getModule(
@@ -44,7 +44,7 @@ class KeyboardControllerPackage : BaseReactPackage() {
44
44
  ReactModuleInfo(
45
45
  StatusBarManagerCompatModuleImpl.NAME,
46
46
  StatusBarManagerCompatModuleImpl.NAME,
47
- false, // canOverrideExistingModule
47
+ true, // canOverrideExistingModule
48
48
  false, // needsEagerInit
49
49
  false, // isCxxModule
50
50
  isTurboModule, // isTurboModule
@@ -54,8 +54,9 @@ class KeyboardControllerPackage : BaseReactPackage() {
54
54
 
55
55
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
56
56
  listOf(
57
- KeyboardControllerViewManager(reactContext),
58
- KeyboardGestureAreaViewManager(reactContext),
59
- OverKeyboardViewManager(reactContext),
57
+ KeyboardControllerViewManager(),
58
+ KeyboardGestureAreaViewManager(),
59
+ OverKeyboardViewManager(),
60
+ KeyboardBackgroundViewManager(),
60
61
  )
61
62
  }
@@ -0,0 +1,19 @@
1
+ package com.reactnativekeyboardcontroller
2
+
3
+ import com.facebook.react.uimanager.ThemedReactContext
4
+ import com.facebook.react.viewmanagers.KeyboardBackgroundViewManagerInterface
5
+ import com.facebook.react.views.view.ReactViewGroup
6
+ import com.facebook.react.views.view.ReactViewManager
7
+ import com.reactnativekeyboardcontroller.managers.KeyboardBackgroundViewManagerImpl
8
+ import com.reactnativekeyboardcontroller.views.background.KeyboardBackgroundViewGroup
9
+
10
+ class KeyboardBackgroundViewManager :
11
+ ReactViewManager(),
12
+ KeyboardBackgroundViewManagerInterface<ReactViewGroup> {
13
+ private val manager = KeyboardBackgroundViewManagerImpl()
14
+
15
+ override fun getName(): String = KeyboardBackgroundViewManagerImpl.NAME
16
+
17
+ override fun createViewInstance(context: ThemedReactContext): KeyboardBackgroundViewGroup =
18
+ manager.createViewInstance(context)
19
+ }
@@ -18,6 +18,10 @@ class KeyboardControllerModule(
18
18
  module.setDefaultMode()
19
19
  }
20
20
 
21
+ override fun preload() {
22
+ module.preload()
23
+ }
24
+
21
25
  override fun dismiss(keepFocus: Boolean) {
22
26
  module.dismiss(keepFocus)
23
27
  }
@@ -1,6 +1,5 @@
1
1
  package com.reactnativekeyboardcontroller
2
2
 
3
- import com.facebook.react.bridge.ReactApplicationContext
4
3
  import com.facebook.react.uimanager.ThemedReactContext
5
4
  import com.facebook.react.uimanager.ViewManagerDelegate
6
5
  import com.facebook.react.uimanager.annotations.ReactProp
@@ -11,11 +10,10 @@ import com.facebook.react.views.view.ReactViewManager
11
10
  import com.reactnativekeyboardcontroller.managers.KeyboardControllerViewManagerImpl
12
11
  import com.reactnativekeyboardcontroller.views.EdgeToEdgeReactViewGroup
13
12
 
14
- class KeyboardControllerViewManager(
15
- mReactContext: ReactApplicationContext,
16
- ) : ReactViewManager(),
13
+ class KeyboardControllerViewManager :
14
+ ReactViewManager(),
17
15
  KeyboardControllerViewManagerInterface<ReactViewGroup> {
18
- private val manager = KeyboardControllerViewManagerImpl(mReactContext)
16
+ private val manager = KeyboardControllerViewManagerImpl()
19
17
  private val mDelegate = KeyboardControllerViewManagerDelegate(this)
20
18
 
21
19
  // region Lifecycle
@@ -1,6 +1,5 @@
1
1
  package com.reactnativekeyboardcontroller
2
2
 
3
- import com.facebook.react.bridge.ReactApplicationContext
4
3
  import com.facebook.react.uimanager.ThemedReactContext
5
4
  import com.facebook.react.uimanager.ViewManagerDelegate
6
5
  import com.facebook.react.uimanager.annotations.ReactProp
@@ -11,11 +10,10 @@ import com.facebook.react.views.view.ReactViewManager
11
10
  import com.reactnativekeyboardcontroller.managers.KeyboardGestureAreaViewManagerImpl
12
11
  import com.reactnativekeyboardcontroller.views.KeyboardGestureAreaReactViewGroup
13
12
 
14
- class KeyboardGestureAreaViewManager(
15
- mReactContext: ReactApplicationContext,
16
- ) : ReactViewManager(),
13
+ class KeyboardGestureAreaViewManager :
14
+ ReactViewManager(),
17
15
  KeyboardGestureAreaManagerInterface<ReactViewGroup> {
18
- private val manager = KeyboardGestureAreaViewManagerImpl(mReactContext)
16
+ private val manager = KeyboardGestureAreaViewManagerImpl()
19
17
  private val mDelegate = KeyboardGestureAreaManagerDelegate(this)
20
18
 
21
19
  override fun getDelegate(): ViewManagerDelegate<ReactViewGroup> = mDelegate
@@ -1,6 +1,5 @@
1
1
  package com.reactnativekeyboardcontroller
2
2
 
3
- import com.facebook.react.bridge.ReactApplicationContext
4
3
  import com.facebook.react.uimanager.LayoutShadowNode
5
4
  import com.facebook.react.uimanager.ReactStylesDiffMap
6
5
  import com.facebook.react.uimanager.StateWrapper
@@ -14,11 +13,10 @@ import com.reactnativekeyboardcontroller.managers.OverKeyboardViewManagerImpl
14
13
  import com.reactnativekeyboardcontroller.views.overlay.OverKeyboardHostShadowNode
15
14
  import com.reactnativekeyboardcontroller.views.overlay.OverKeyboardHostView
16
15
 
17
- class OverKeyboardViewManager(
18
- mReactContext: ReactApplicationContext,
19
- ) : ViewGroupManager<OverKeyboardHostView>(),
16
+ class OverKeyboardViewManager :
17
+ ViewGroupManager<OverKeyboardHostView>(),
20
18
  OverKeyboardViewManagerInterface<OverKeyboardHostView> {
21
- private val manager = OverKeyboardViewManagerImpl(mReactContext)
19
+ private val manager = OverKeyboardViewManagerImpl()
22
20
  private val mDelegate = OverKeyboardViewManagerDelegate(this)
23
21
 
24
22
  override fun getDelegate(): ViewManagerDelegate<OverKeyboardHostView> = mDelegate
@@ -1,7 +1,7 @@
1
1
  package com.reactnativekeyboardcontroller
2
2
 
3
3
  import com.facebook.react.bridge.ReactApplicationContext
4
- import com.reactnativekeyboardcontroller.modules.StatusBarManagerCompatModuleImpl
4
+ import com.reactnativekeyboardcontroller.modules.statusbar.StatusBarManagerCompatModuleImpl
5
5
 
6
6
  class StatusBarManagerCompatModule(
7
7
  mReactContext: ReactApplicationContext,
@@ -10,6 +10,8 @@ class StatusBarManagerCompatModule(
10
10
 
11
11
  override fun getName(): String = StatusBarManagerCompatModuleImpl.NAME
12
12
 
13
+ override fun getConstants(): MutableMap<String, Any>? = module.getConstants()
14
+
13
15
  override fun setHidden(hidden: Boolean) {
14
16
  module.setHidden(hidden)
15
17
  }
@@ -1,9 +1,11 @@
1
1
  package com.reactnativekeyboardcontroller.extensions
2
2
 
3
3
  import android.annotation.SuppressLint
4
+ import android.content.ComponentName
4
5
  import android.content.Context
5
6
  import android.graphics.Point
6
7
  import android.os.Build
8
+ import android.provider.Settings
7
9
  import android.view.Display
8
10
  import android.view.WindowManager
9
11
  import android.view.WindowMetrics
@@ -36,3 +38,21 @@ fun Context.getDisplaySize(): Point {
36
38
 
37
39
  return size
38
40
  }
41
+
42
+ fun Context.isSystemDarkMode(): Boolean =
43
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
44
+ (getSystemService(Context.UI_MODE_SERVICE) as? android.app.UiModeManager)
45
+ ?.nightMode == android.app.UiModeManager.MODE_NIGHT_YES
46
+ } else {
47
+ false
48
+ }
49
+
50
+ fun Context.currentImePackage(): String? {
51
+ val id =
52
+ Settings.Secure.getString(
53
+ contentResolver,
54
+ Settings.Secure.DEFAULT_INPUT_METHOD,
55
+ ) ?: return null
56
+
57
+ return ComponentName.unflattenFromString(id)?.packageName
58
+ }
@@ -1,7 +1,5 @@
1
1
  package com.reactnativekeyboardcontroller.extensions
2
2
 
3
- import android.content.Context
4
- import android.os.Build
5
3
  import com.facebook.react.bridge.Arguments
6
4
  import com.facebook.react.bridge.ReactContext
7
5
  import com.facebook.react.bridge.WritableMap
@@ -55,15 +53,7 @@ fun ThemedReactContext?.keepShadowNodesInSync(viewId: Int) {
55
53
  val ThemedReactContext?.appearance: String
56
54
  get() =
57
55
  when {
58
- this == null -> "default"
59
- isSystemDarkMode(this) -> "dark"
56
+ this == null -> "light"
57
+ isSystemDarkMode() -> "dark"
60
58
  else -> "light"
61
59
  }
62
-
63
- private fun isSystemDarkMode(context: Context): Boolean =
64
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
65
- (context.getSystemService(Context.UI_MODE_SERVICE) as? android.app.UiModeManager)
66
- ?.nightMode == android.app.UiModeManager.MODE_NIGHT_YES
67
- } else {
68
- false
69
- }
@@ -0,0 +1,13 @@
1
+ package com.reactnativekeyboardcontroller.managers
2
+
3
+ import com.facebook.react.uimanager.ThemedReactContext
4
+ import com.reactnativekeyboardcontroller.views.background.KeyboardBackgroundViewGroup
5
+
6
+ class KeyboardBackgroundViewManagerImpl {
7
+ fun createViewInstance(reactContext: ThemedReactContext): KeyboardBackgroundViewGroup =
8
+ KeyboardBackgroundViewGroup(reactContext)
9
+
10
+ companion object {
11
+ const val NAME = "KeyboardBackgroundView"
12
+ }
13
+ }
@@ -1,6 +1,5 @@
1
1
  package com.reactnativekeyboardcontroller.managers
2
2
 
3
- import com.facebook.react.bridge.ReactApplicationContext
4
3
  import com.facebook.react.common.MapBuilder
5
4
  import com.facebook.react.uimanager.ThemedReactContext
6
5
  import com.reactnativekeyboardcontroller.events.FocusedInputLayoutChangedEvent
@@ -10,10 +9,7 @@ import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent
10
9
  import com.reactnativekeyboardcontroller.listeners.WindowDimensionListener
11
10
  import com.reactnativekeyboardcontroller.views.EdgeToEdgeReactViewGroup
12
11
 
13
- @Suppress("detekt:UnusedPrivateProperty")
14
- class KeyboardControllerViewManagerImpl(
15
- mReactContext: ReactApplicationContext,
16
- ) {
12
+ class KeyboardControllerViewManagerImpl {
17
13
  private var listener: WindowDimensionListener? = null
18
14
 
19
15
  fun createViewInstance(reactContext: ThemedReactContext): EdgeToEdgeReactViewGroup {
@@ -32,7 +28,7 @@ class KeyboardControllerViewManagerImpl(
32
28
  view: EdgeToEdgeReactViewGroup,
33
29
  enabled: Boolean,
34
30
  ) {
35
- view.setActive(enabled)
31
+ view.active = enabled
36
32
  }
37
33
 
38
34
  fun setStatusBarTranslucent(
@@ -1,13 +1,9 @@
1
1
  package com.reactnativekeyboardcontroller.managers
2
2
 
3
- import com.facebook.react.bridge.ReactApplicationContext
4
3
  import com.facebook.react.uimanager.ThemedReactContext
5
4
  import com.reactnativekeyboardcontroller.views.KeyboardGestureAreaReactViewGroup
6
5
 
7
- @Suppress("detekt:UnusedPrivateProperty")
8
- class KeyboardGestureAreaViewManagerImpl(
9
- mReactContext: ReactApplicationContext,
10
- ) {
6
+ class KeyboardGestureAreaViewManagerImpl {
11
7
  fun createViewInstance(reactContext: ThemedReactContext): KeyboardGestureAreaReactViewGroup =
12
8
  KeyboardGestureAreaReactViewGroup(reactContext)
13
9
 
@@ -1,13 +1,9 @@
1
1
  package com.reactnativekeyboardcontroller.managers
2
2
 
3
- import com.facebook.react.bridge.ReactApplicationContext
4
3
  import com.facebook.react.uimanager.ThemedReactContext
5
4
  import com.reactnativekeyboardcontroller.views.overlay.OverKeyboardHostView
6
5
 
7
- @Suppress("detekt:UnusedPrivateProperty")
8
- class OverKeyboardViewManagerImpl(
9
- mReactContext: ReactApplicationContext,
10
- ) {
6
+ class OverKeyboardViewManagerImpl {
11
7
  fun createViewInstance(reactContext: ThemedReactContext): OverKeyboardHostView = OverKeyboardHostView(reactContext)
12
8
 
13
9
  fun setVisible(
@@ -22,6 +22,10 @@ class KeyboardControllerModuleImpl(
22
22
  setSoftInputMode(mDefaultMode)
23
23
  }
24
24
 
25
+ fun preload() {
26
+ // no-op on Android
27
+ }
28
+
25
29
  fun dismiss(keepFocus: Boolean) {
26
30
  val activity = mReactContext.currentActivity
27
31
  val view: View? = FocusedInputHolder.get()
@@ -1,4 +1,4 @@
1
- package com.reactnativekeyboardcontroller.modules
1
+ package com.reactnativekeyboardcontroller.modules.statusbar
2
2
 
3
3
  import android.animation.ArgbEvaluator
4
4
  import android.animation.ValueAnimator
@@ -19,10 +19,15 @@ private val TAG = StatusBarManagerCompatModuleImpl::class.qualifiedName
19
19
  class StatusBarManagerCompatModuleImpl(
20
20
  private val mReactContext: ReactApplicationContext,
21
21
  ) {
22
+ private var original = StatusBarModuleProxy(mReactContext)
22
23
  private var controller: WindowInsetsControllerCompat? = null
23
24
  private var lastActivity = WeakReference<Activity?>(null)
24
25
 
25
26
  fun setHidden(hidden: Boolean) {
27
+ if (!isEnabled()) {
28
+ return original.setHidden(hidden)
29
+ }
30
+
26
31
  UiThreadUtil.runOnUiThread {
27
32
  if (hidden) {
28
33
  getController()?.hide(WindowInsetsCompat.Type.statusBars())
@@ -37,9 +42,16 @@ class StatusBarManagerCompatModuleImpl(
37
42
  color: Int,
38
43
  animated: Boolean,
39
44
  ) {
45
+ if (!isEnabled()) {
46
+ return original.setColor(color.toDouble(), animated)
47
+ }
48
+
40
49
  val activity = mReactContext.currentActivity
41
50
  if (activity == null) {
42
- Logger.w(TAG, "StatusBarManagerCompatModule: Ignored status bar change, current activity is null.")
51
+ Logger.w(
52
+ TAG,
53
+ "StatusBarManagerCompatModule: Ignored status bar change, current activity is null.",
54
+ )
43
55
  return
44
56
  }
45
57
 
@@ -61,18 +73,27 @@ class StatusBarManagerCompatModuleImpl(
61
73
  }
62
74
 
63
75
  fun setTranslucent(translucent: Boolean) {
76
+ if (!isEnabled()) {
77
+ return original.setTranslucent(translucent)
78
+ }
79
+
64
80
  UiThreadUtil.runOnUiThread {
65
- val view = mReactContext.rootView?.findViewWithTag<EdgeToEdgeReactViewGroup>(EdgeToEdgeReactViewGroup.VIEW_TAG)
66
- view?.forceStatusBarTranslucent(translucent)
81
+ view()?.forceStatusBarTranslucent(translucent)
67
82
  }
68
83
  }
69
84
 
70
85
  fun setStyle(style: String) {
86
+ if (!isEnabled()) {
87
+ return original.setStyle(style)
88
+ }
89
+
71
90
  UiThreadUtil.runOnUiThread {
72
91
  getController()?.isAppearanceLightStatusBars = style == "dark-content"
73
92
  }
74
93
  }
75
94
 
95
+ fun getConstants(): MutableMap<String, Any>? = original.getConstants()
96
+
76
97
  private fun getController(): WindowInsetsControllerCompat? {
77
98
  val activity = mReactContext.currentActivity
78
99
 
@@ -94,8 +115,13 @@ class StatusBarManagerCompatModuleImpl(
94
115
  return this.controller
95
116
  }
96
117
 
118
+ private fun isEnabled(): Boolean = view()?.active ?: false
119
+
120
+ private fun view(): EdgeToEdgeReactViewGroup? =
121
+ mReactContext.rootView?.findViewWithTag<EdgeToEdgeReactViewGroup>(EdgeToEdgeReactViewGroup.VIEW_TAG)
122
+
97
123
  companion object {
98
- const val NAME = "StatusBarManagerCompat"
124
+ const val NAME = "StatusBarManager"
99
125
  private const val DEFAULT_ANIMATION_TIME = 300L
100
126
  }
101
127
  }
@@ -0,0 +1,86 @@
1
+ @file:Suppress("detekt:TooGenericExceptionCaught")
2
+
3
+ package com.reactnativekeyboardcontroller.modules.statusbar
4
+
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.reactnativekeyboardcontroller.log.Logger
7
+ import java.lang.reflect.Method
8
+
9
+ private val TAG = StatusBarModuleProxy::class.qualifiedName
10
+
11
+ /**
12
+ * For the sake of better compatibility with the old/new version of the react-native, we are using reflection
13
+ * to call the methods of the module. In RN 0.78 the `StatusBarModule` was public, but in RN 0.80
14
+ * it's internal (kotlin-only). So we are using reflection to call the methods of the module.
15
+ */
16
+ class StatusBarModuleProxy(
17
+ reactContext: ReactApplicationContext,
18
+ ) {
19
+ private var instance: Any? = null
20
+
21
+ private var setHiddenMethod: Method? = null
22
+ private var setColorMethod: Method? = null
23
+ private var setTranslucentMethod: Method? = null
24
+ private var setStyleMethod: Method? = null
25
+ private var getConstantsMethod: Method? = null
26
+
27
+ init {
28
+ try {
29
+ val clazz = Class.forName("com.facebook.react.modules.statusbar.StatusBarModule")
30
+ val constructor = clazz.getConstructor(ReactApplicationContext::class.java)
31
+ instance = constructor.newInstance(reactContext)
32
+
33
+ setHiddenMethod = clazz.getMethod("setHidden", Boolean::class.java)
34
+ setColorMethod = clazz.getMethod("setColor", Double::class.java, Boolean::class.java)
35
+ setTranslucentMethod = clazz.getMethod("setTranslucent", Boolean::class.java)
36
+ setStyleMethod = clazz.getMethod("setStyle", String::class.java)
37
+ getConstantsMethod = clazz.getMethod("getConstants")
38
+ } catch (e: Exception) {
39
+ Logger.w(TAG, "Failed to initialize StatusBarModule via reflection", e)
40
+ }
41
+ }
42
+
43
+ fun setHidden(hidden: Boolean) {
44
+ try {
45
+ setHiddenMethod?.invoke(instance, hidden)
46
+ } catch (e: Exception) {
47
+ Logger.w(TAG, "Error invoking StatusBarModule.setHidden method", e)
48
+ }
49
+ }
50
+
51
+ fun setColor(
52
+ color: Double,
53
+ animated: Boolean,
54
+ ) {
55
+ try {
56
+ setColorMethod?.invoke(instance, color, animated)
57
+ } catch (e: Exception) {
58
+ Logger.w(TAG, "Error invoking StatusBarModule.setColor method", e)
59
+ }
60
+ }
61
+
62
+ fun setTranslucent(translucent: Boolean) {
63
+ try {
64
+ setTranslucentMethod?.invoke(instance, translucent)
65
+ } catch (e: Exception) {
66
+ Logger.w(TAG, "Error invoking StatusBarModule.setTranslucent method", e)
67
+ }
68
+ }
69
+
70
+ fun setStyle(style: String) {
71
+ try {
72
+ setStyleMethod?.invoke(instance, style)
73
+ } catch (e: Exception) {
74
+ Logger.w(TAG, "Error invoking StatusBarModule.setStyle method", e)
75
+ }
76
+ }
77
+
78
+ fun getConstants(): MutableMap<String, Any>? =
79
+ try {
80
+ @Suppress("UNCHECKED_CAST")
81
+ getConstantsMethod?.invoke(instance) as? MutableMap<String, Any>
82
+ } catch (e: Exception) {
83
+ Logger.w(TAG, "Error invoking StatusBarModule.getConstants method", e)
84
+ null
85
+ }
86
+ }
@@ -31,8 +31,16 @@ class EdgeToEdgeReactViewGroup(
31
31
  private var isStatusBarTranslucent = false
32
32
  private var isNavigationBarTranslucent = false
33
33
  private var isPreservingEdgeToEdge = false
34
- private var active = false
35
34
  private var isEdgeToEdge = false
35
+ var active: Boolean = false
36
+ set(value) {
37
+ field = value
38
+ if (value) {
39
+ enable()
40
+ } else {
41
+ disable()
42
+ }
43
+ }
36
44
 
37
45
  // internal class members
38
46
  private var eventView: ReactViewGroup? = null
@@ -223,16 +231,6 @@ class EdgeToEdgeReactViewGroup(
223
231
  fun setPreserveEdgeToEdge(isPreservingEdgeToEdge: Boolean) {
224
232
  this.isPreservingEdgeToEdge = isPreservingEdgeToEdge
225
233
  }
226
-
227
- fun setActive(active: Boolean) {
228
- this.active = active
229
-
230
- if (active) {
231
- this.enable()
232
- } else {
233
- this.disable()
234
- }
235
- }
236
234
  // endregion
237
235
 
238
236
  // region external methods
@@ -0,0 +1,35 @@
1
+ package com.reactnativekeyboardcontroller.views.background
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.res.Configuration
5
+ import android.view.WindowInsets
6
+ import com.facebook.react.uimanager.BackgroundStyleApplicator
7
+ import com.facebook.react.uimanager.ThemedReactContext
8
+ import com.facebook.react.views.view.ReactViewGroup
9
+
10
+ @SuppressLint("ViewConstructor")
11
+ class KeyboardBackgroundViewGroup(
12
+ private val reactContext: ThemedReactContext,
13
+ ) : ReactViewGroup(reactContext) {
14
+ // view mounted
15
+ override fun onAttachedToWindow() {
16
+ super.onAttachedToWindow()
17
+ BackgroundStyleApplicator.setBackgroundColor(this, reactContext.getInputMethodColor())
18
+ }
19
+
20
+ // theme changed
21
+ override fun onConfigurationChanged(newConfig: Configuration?) {
22
+ super.onConfigurationChanged(newConfig)
23
+ BackgroundStyleApplicator.setBackgroundColor(this, reactContext.getInputMethodColor())
24
+ }
25
+
26
+ // keyboard changed
27
+ override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
28
+ BackgroundStyleApplicator.setBackgroundColor(this, reactContext.getInputMethodColor())
29
+ return super.onApplyWindowInsets(insets)
30
+ }
31
+
32
+ override fun setBackgroundColor(color: Int) {
33
+ // do nothing, since we manage background color on our own
34
+ }
35
+ }
@@ -0,0 +1,91 @@
1
+ package com.reactnativekeyboardcontroller.views.background
2
+
3
+ import android.content.Context
4
+ import android.graphics.Color
5
+ import android.os.Build
6
+ import androidx.annotation.ColorInt
7
+ import com.facebook.react.uimanager.ThemedReactContext
8
+ import com.reactnativekeyboardcontroller.R
9
+ import com.reactnativekeyboardcontroller.extensions.currentImePackage
10
+ import com.reactnativekeyboardcontroller.extensions.isSystemDarkMode
11
+ import com.reactnativekeyboardcontroller.log.Logger
12
+
13
+ private const val TAG = "Skins"
14
+ private const val MAX_RGB_VALUE = 255
15
+
16
+ object ImePackages {
17
+ const val AOSP = "com.android.inputmethod.latin"
18
+ const val GBOARD = "com.google.android.inputmethod.latin"
19
+ const val SWIFT_KEY = "com.touchtype.swiftkey"
20
+ const val GBOARD_TTS = "com.google.android.googlequicksearchbox"
21
+ const val GOOGLE_TTS = "com.google.android.tts"
22
+ const val YANDEX = "ru.yandex.androidkeyboard"
23
+ const val SAMSUNG = "com.samsung.android.honeyboard"
24
+ }
25
+
26
+ val imeColorMap: Map<String, Pair<Int, Int>> =
27
+ mapOf(
28
+ ImePackages.AOSP to (R.style.aosp_light to R.style.aosp_light),
29
+ ImePackages.GBOARD to (R.style.gboard_light to R.style.gboard_dark),
30
+ ImePackages.SWIFT_KEY to (R.style.swiftkey_light to R.style.swiftkey_dark),
31
+ ImePackages.GBOARD_TTS to (R.style.gboard_tts_light to R.style.gboard_tts_dark),
32
+ ImePackages.GOOGLE_TTS to (R.style.gboard_tts_light to R.style.gboard_tts_dark),
33
+ ImePackages.YANDEX to (R.style.yandex_light to R.style.yandex_dark),
34
+ ImePackages.SAMSUNG to (R.style.samsung_light to R.style.samsung_dark),
35
+ )
36
+
37
+ data class ColorProperties(
38
+ @ColorInt val color: Int,
39
+ val tone: Int = 0,
40
+ ) {
41
+ @get:ColorInt
42
+ val blend: Int
43
+ get() = shiftRgbChannels(color, tone)
44
+ }
45
+
46
+ fun Context.getColorProperties(styleResId: Int): ColorProperties {
47
+ val attrs = obtainStyledAttributes(styleResId, R.styleable.ColorProperties)
48
+ try {
49
+ return ColorProperties(
50
+ color = attrs.getColor(R.styleable.ColorProperties_color, Color.BLACK),
51
+ tone = attrs.getInt(R.styleable.ColorProperties_tone, 0),
52
+ )
53
+ } finally {
54
+ attrs.recycle()
55
+ }
56
+ }
57
+
58
+ @ColorInt
59
+ fun shiftRgbChannels(
60
+ @ColorInt color: Int,
61
+ shift: Int = 4,
62
+ ): Int {
63
+ val red = (Color.red(color) + shift).coerceIn(0, MAX_RGB_VALUE)
64
+ val green = (Color.green(color) + shift).coerceIn(0, MAX_RGB_VALUE)
65
+ val blue = (Color.blue(color) + shift).coerceIn(0, MAX_RGB_VALUE)
66
+
67
+ return Color.argb(
68
+ Color.alpha(color),
69
+ red,
70
+ green,
71
+ blue,
72
+ )
73
+ }
74
+
75
+ @ColorInt
76
+ fun ThemedReactContext.getInputMethodColor(): Int {
77
+ val imePackage = currentImePackage()
78
+ val isDark = isSystemDarkMode()
79
+
80
+ Logger.i(TAG, "Current IME: $imePackage")
81
+
82
+ val (lightColorRes, darkColorRes) =
83
+ imeColorMap[imePackage]
84
+ ?: (R.style.gboard_light to R.style.gboard_dark)
85
+
86
+ // on Android 10 dark theme doesn't affect keyboard color
87
+ val resId = if (isDark && Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) darkColorRes else lightColorRes
88
+ val color = getColorProperties(resId).blend
89
+
90
+ return color
91
+ }
@@ -13,6 +13,7 @@
13
13
  #include <react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardControllerViewComponentDescriptor.h>
14
14
  #include <react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardGestureAreaComponentDescriptor.h>
15
15
  #include <react/renderer/components/reactnativekeyboardcontroller/RNKCOverKeyboardViewComponentDescriptor.h>
16
+ #include <react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardBackgroundViewComponentDescriptor.h>
16
17
 
17
18
  #include <memory>
18
19
  #include <string>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <declare-styleable name="ColorProperties">
4
+ <attr name="color" format="color" />
5
+ <attr name="tone" format="integer" />
6
+ </declare-styleable>
7
+ </resources>