react-native-keyboard-controller 1.21.0-beta.2 → 1.21.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 (214) hide show
  1. package/README.md +1 -0
  2. package/android/src/base/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +1 -0
  3. package/android/src/fabric/java/com/reactnativekeyboardcontroller/ClippingScrollViewDecoratorViewManager.kt +14 -0
  4. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +8 -0
  5. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardToolbarGroupViewManager.kt +23 -0
  6. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +12 -0
  7. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt +2 -1
  8. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt +5 -1
  9. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardToolbarGroupViewManagerImpl.kt +13 -0
  10. package/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt +4 -6
  11. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +26 -0
  12. package/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt +31 -4
  13. package/android/src/main/java/com/reactnativekeyboardcontroller/views/ClippingScrollViewDecoratorView.kt +33 -1
  14. package/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardToolbarGroupReactViewGroup.kt +13 -0
  15. package/android/src/main/jni/RNKC.h +2 -0
  16. package/android/src/paper/java/com/reactnativekeyboardcontroller/ClippingScrollViewDecoratorViewManager.kt +16 -0
  17. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +9 -0
  18. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardToolbarGroupViewManager.kt +15 -0
  19. package/android/src/turbo/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +2 -0
  20. package/common/cpp/react/renderer/components/RNKC/RNKCClippingScrollViewDecoratorViewComponentDescriptor.h +27 -0
  21. package/common/cpp/react/renderer/components/RNKC/RNKCClippingScrollViewDecoratorViewShadowNode.cpp +14 -0
  22. package/common/cpp/react/renderer/components/RNKC/RNKCClippingScrollViewDecoratorViewShadowNode.h +30 -0
  23. package/common/cpp/react/renderer/components/RNKC/RNKCClippingScrollViewDecoratorViewState.h +28 -0
  24. package/common/cpp/react/renderer/components/RNKC/RNKCKeyboardToolbarGroupViewComponentDescriptor.h +20 -0
  25. package/common/cpp/react/renderer/components/RNKC/RNKCKeyboardToolbarGroupViewShadowNode.cpp +7 -0
  26. package/common/cpp/react/renderer/components/RNKC/RNKCKeyboardToolbarGroupViewShadowNode.h +23 -0
  27. package/common/cpp/react/renderer/components/RNKC/RNKCKeyboardToolbarGroupViewState.h +21 -0
  28. package/ios/KeyboardControllerModule.mm +36 -0
  29. package/ios/animations/KeyboardAnimation.swift +2 -2
  30. package/ios/animations/SpringAnimation.swift +1 -1
  31. package/ios/animations/TimingAnimation.swift +1 -3
  32. package/ios/delegates/KCTextInputCompositeDelegate.swift +2 -2
  33. package/ios/extensions/CGFloat.swift +1 -3
  34. package/ios/extensions/UIApplication.swift +1 -1
  35. package/ios/interactive/KeyboardAreaExtender.swift +2 -1
  36. package/ios/observers/FocusedInputObserver.swift +6 -3
  37. package/ios/observers/movement/KeyboardTrackingView.swift +4 -1
  38. package/ios/observers/movement/observer/KeyboardMovementObserver+Interactive.swift +2 -0
  39. package/ios/observers/movement/observer/KeyboardMovementObserver+Listeners.swift +30 -7
  40. package/ios/observers/movement/observer/KeyboardMovementObserver.swift +2 -48
  41. package/ios/protocols/TextInput.swift +1 -1
  42. package/ios/swizzling/UIResponderSwizzle.swift +2 -4
  43. package/ios/traversal/FocusedInputHolder.swift +3 -3
  44. package/ios/traversal/KeyboardView.swift +1 -1
  45. package/ios/traversal/ViewHierarchyNavigator.swift +51 -5
  46. package/ios/views/ClippingScrollViewDecoratorViewManager.h +26 -0
  47. package/ios/views/ClippingScrollViewDecoratorViewManager.mm +231 -0
  48. package/ios/views/KeyboardControllerViewManager.swift +5 -5
  49. package/ios/views/KeyboardToolbarGroupViewManager.h +28 -0
  50. package/ios/views/KeyboardToolbarGroupViewManager.mm +88 -0
  51. package/jest/index.js +12 -4
  52. package/lib/commonjs/bindings.js +18 -2
  53. package/lib/commonjs/bindings.js.map +1 -1
  54. package/lib/commonjs/bindings.native.js +3 -4
  55. package/lib/commonjs/bindings.native.js.map +1 -1
  56. package/lib/commonjs/components/KeyboardAvoidingView/index.js +30 -4
  57. package/lib/commonjs/components/KeyboardAvoidingView/index.js.map +1 -1
  58. package/lib/commonjs/components/KeyboardAwareScrollView/index.js +55 -14
  59. package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
  60. package/lib/commonjs/components/{ChatKit → KeyboardChatScrollView}/hooks.js.map +1 -1
  61. package/lib/commonjs/components/KeyboardChatScrollView/index.js +111 -0
  62. package/lib/commonjs/components/KeyboardChatScrollView/index.js.map +1 -0
  63. package/lib/commonjs/components/KeyboardChatScrollView/types.js.map +1 -0
  64. package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/helpers.js +221 -0
  65. package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/helpers.js.map +1 -0
  66. package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js +149 -0
  67. package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js.map +1 -0
  68. package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.js +240 -0
  69. package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.js.map +1 -0
  70. package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/types.js +6 -0
  71. package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/types.js.map +1 -0
  72. package/lib/commonjs/components/KeyboardChatScrollView/useExtraContentPadding/index.js +72 -0
  73. package/lib/commonjs/components/KeyboardChatScrollView/useExtraContentPadding/index.js.map +1 -0
  74. package/lib/commonjs/components/KeyboardStickyView/index.js +3 -1
  75. package/lib/commonjs/components/KeyboardStickyView/index.js.map +1 -1
  76. package/lib/commonjs/components/KeyboardToolbar/index.js +1 -0
  77. package/lib/commonjs/components/KeyboardToolbar/index.js.map +1 -1
  78. package/lib/commonjs/components/ScrollViewWithBottomPadding/index.js +36 -15
  79. package/lib/commonjs/components/ScrollViewWithBottomPadding/index.js.map +1 -1
  80. package/lib/commonjs/components/hooks/useScrollState.js +20 -1
  81. package/lib/commonjs/components/hooks/useScrollState.js.map +1 -1
  82. package/lib/commonjs/components/index.js +7 -7
  83. package/lib/commonjs/components/index.js.map +1 -1
  84. package/lib/commonjs/index.js +7 -7
  85. package/lib/commonjs/index.js.map +1 -1
  86. package/lib/commonjs/specs/ClippingScrollViewDecoratorViewNativeComponent.js +1 -2
  87. package/lib/commonjs/specs/ClippingScrollViewDecoratorViewNativeComponent.js.map +1 -1
  88. package/lib/commonjs/specs/KeyboardToolbarGroupViewNativeComponent.js +12 -0
  89. package/lib/commonjs/specs/KeyboardToolbarGroupViewNativeComponent.js.map +1 -0
  90. package/lib/commonjs/specs/NativeKeyboardController.js.map +1 -1
  91. package/lib/commonjs/types/module.js.map +1 -1
  92. package/lib/commonjs/types/views.js.map +1 -1
  93. package/lib/module/bindings.js +17 -1
  94. package/lib/module/bindings.js.map +1 -1
  95. package/lib/module/bindings.native.js +2 -3
  96. package/lib/module/bindings.native.js.map +1 -1
  97. package/lib/module/components/KeyboardAvoidingView/index.js +29 -4
  98. package/lib/module/components/KeyboardAvoidingView/index.js.map +1 -1
  99. package/lib/module/components/KeyboardAwareScrollView/index.js +55 -14
  100. package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
  101. package/lib/module/components/{ChatKit → KeyboardChatScrollView}/hooks.js.map +1 -1
  102. package/lib/module/components/KeyboardChatScrollView/index.js +104 -0
  103. package/lib/module/components/KeyboardChatScrollView/index.js.map +1 -0
  104. package/lib/module/components/KeyboardChatScrollView/types.js.map +1 -0
  105. package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/helpers.js +207 -0
  106. package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/helpers.js.map +1 -0
  107. package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js +143 -0
  108. package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js.map +1 -0
  109. package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.js +234 -0
  110. package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.js.map +1 -0
  111. package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/types.js +2 -0
  112. package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/types.js.map +1 -0
  113. package/lib/module/components/KeyboardChatScrollView/useExtraContentPadding/index.js +67 -0
  114. package/lib/module/components/KeyboardChatScrollView/useExtraContentPadding/index.js.map +1 -0
  115. package/lib/module/components/KeyboardStickyView/index.js +3 -1
  116. package/lib/module/components/KeyboardStickyView/index.js.map +1 -1
  117. package/lib/module/components/KeyboardToolbar/index.js +2 -1
  118. package/lib/module/components/KeyboardToolbar/index.js.map +1 -1
  119. package/lib/module/components/ScrollViewWithBottomPadding/index.js +38 -17
  120. package/lib/module/components/ScrollViewWithBottomPadding/index.js.map +1 -1
  121. package/lib/module/components/hooks/useScrollState.js +21 -2
  122. package/lib/module/components/hooks/useScrollState.js.map +1 -1
  123. package/lib/module/components/index.js +1 -1
  124. package/lib/module/components/index.js.map +1 -1
  125. package/lib/module/index.js +1 -1
  126. package/lib/module/index.js.map +1 -1
  127. package/lib/module/specs/ClippingScrollViewDecoratorViewNativeComponent.js +1 -2
  128. package/lib/module/specs/ClippingScrollViewDecoratorViewNativeComponent.js.map +1 -1
  129. package/lib/module/specs/KeyboardToolbarGroupViewNativeComponent.js +5 -0
  130. package/lib/module/specs/KeyboardToolbarGroupViewNativeComponent.js.map +1 -0
  131. package/lib/module/specs/NativeKeyboardController.js.map +1 -1
  132. package/lib/module/types/module.js.map +1 -1
  133. package/lib/module/types/views.js.map +1 -1
  134. package/lib/typescript/bindings.d.ts +12 -2
  135. package/lib/typescript/bindings.native.d.ts +2 -1
  136. package/lib/typescript/components/KeyboardAvoidingView/index.d.ts +44 -13
  137. package/lib/typescript/components/KeyboardChatScrollView/hooks.d.ts +2 -0
  138. package/lib/typescript/components/KeyboardChatScrollView/index.d.ts +15 -0
  139. package/lib/typescript/components/{ChatKit → KeyboardChatScrollView}/types.d.ts +46 -6
  140. package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/helpers.d.ts +132 -0
  141. package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/index.d.ts +18 -0
  142. package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/index.ios.d.ts +21 -0
  143. package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/types.d.ts +37 -0
  144. package/lib/typescript/components/KeyboardChatScrollView/useExtraContentPadding/index.d.ts +43 -0
  145. package/lib/typescript/components/KeyboardToolbar/index.d.ts +2 -0
  146. package/lib/typescript/components/ScrollViewWithBottomPadding/index.d.ts +5 -4
  147. package/lib/typescript/components/hooks/useScrollState.d.ts +3 -0
  148. package/lib/typescript/components/index.d.ts +2 -2
  149. package/lib/typescript/index.d.ts +2 -2
  150. package/lib/typescript/specs/ClippingScrollViewDecoratorViewNativeComponent.d.ts +2 -0
  151. package/lib/typescript/specs/KeyboardToolbarGroupViewNativeComponent.d.ts +6 -0
  152. package/lib/typescript/specs/NativeKeyboardController.d.ts +1 -0
  153. package/lib/typescript/types/module.d.ts +7 -0
  154. package/lib/typescript/types/views.d.ts +4 -0
  155. package/package.json +6 -2
  156. package/react-native.config.js +2 -0
  157. package/src/bindings.native.ts +4 -4
  158. package/src/bindings.ts +15 -1
  159. package/src/components/KeyboardAvoidingView/index.tsx +56 -29
  160. package/src/components/KeyboardAwareScrollView/index.tsx +68 -13
  161. package/src/components/KeyboardChatScrollView/hooks.ts +2 -0
  162. package/src/components/KeyboardChatScrollView/index.tsx +150 -0
  163. package/src/components/{ChatKit → KeyboardChatScrollView}/types.ts +46 -6
  164. package/src/components/KeyboardChatScrollView/useChatKeyboard/helpers.ts +268 -0
  165. package/src/components/KeyboardChatScrollView/useChatKeyboard/index.ios.ts +260 -0
  166. package/src/components/KeyboardChatScrollView/useChatKeyboard/index.ts +376 -0
  167. package/src/components/KeyboardChatScrollView/useChatKeyboard/types.ts +39 -0
  168. package/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts +123 -0
  169. package/src/components/KeyboardStickyView/index.tsx +4 -3
  170. package/src/components/KeyboardToolbar/index.tsx +6 -1
  171. package/src/components/ScrollViewWithBottomPadding/index.tsx +53 -29
  172. package/src/components/hooks/useScrollState.ts +24 -2
  173. package/src/components/index.ts +2 -2
  174. package/src/index.ts +2 -2
  175. package/src/specs/ClippingScrollViewDecoratorViewNativeComponent.ts +2 -1
  176. package/src/specs/KeyboardToolbarGroupViewNativeComponent.ts +10 -0
  177. package/src/specs/NativeKeyboardController.ts +1 -0
  178. package/src/types/module.ts +9 -0
  179. package/src/types/views.ts +4 -0
  180. package/android/.settings/org.eclipse.buildship.core.prefs +0 -2
  181. package/ios/KeyboardController.xcodeproj/xcuserdata/kirylziusko.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  182. package/ios/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  183. package/ios/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  184. package/ios/Tests/Tests.xcodeproj/project.xcworkspace/xcuserdata/kirylziusko.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  185. package/ios/Tests/Tests.xcodeproj/xcuserdata/kirylziusko.xcuserdatad/xcschemes/xcschememanagement.plist +0 -32
  186. package/lib/commonjs/components/ChatKit/TODO.md +0 -20
  187. package/lib/commonjs/components/ChatKit/index.js +0 -55
  188. package/lib/commonjs/components/ChatKit/index.js.map +0 -1
  189. package/lib/commonjs/components/ChatKit/types.js.map +0 -1
  190. package/lib/commonjs/components/ChatKit/useChatKeyboard/helpers.js +0 -101
  191. package/lib/commonjs/components/ChatKit/useChatKeyboard/helpers.js.map +0 -1
  192. package/lib/commonjs/components/ChatKit/useChatKeyboard/index.js +0 -147
  193. package/lib/commonjs/components/ChatKit/useChatKeyboard/index.js.map +0 -1
  194. package/lib/module/components/ChatKit/TODO.md +0 -20
  195. package/lib/module/components/ChatKit/index.js +0 -48
  196. package/lib/module/components/ChatKit/index.js.map +0 -1
  197. package/lib/module/components/ChatKit/types.js.map +0 -1
  198. package/lib/module/components/ChatKit/useChatKeyboard/helpers.js +0 -92
  199. package/lib/module/components/ChatKit/useChatKeyboard/helpers.js.map +0 -1
  200. package/lib/module/components/ChatKit/useChatKeyboard/index.js +0 -141
  201. package/lib/module/components/ChatKit/useChatKeyboard/index.js.map +0 -1
  202. package/lib/typescript/components/ChatKit/hooks.d.ts +0 -2
  203. package/lib/typescript/components/ChatKit/index.d.ts +0 -14
  204. package/lib/typescript/components/ChatKit/useChatKeyboard/helpers.d.ts +0 -57
  205. package/lib/typescript/components/ChatKit/useChatKeyboard/index.d.ts +0 -36
  206. package/src/components/ChatKit/TODO.md +0 -20
  207. package/src/components/ChatKit/hooks.ts +0 -2
  208. package/src/components/ChatKit/index.tsx +0 -63
  209. package/src/components/ChatKit/useChatKeyboard/helpers.ts +0 -118
  210. package/src/components/ChatKit/useChatKeyboard/index.ts +0 -228
  211. /package/lib/commonjs/components/{ChatKit → KeyboardChatScrollView}/hooks.js +0 -0
  212. /package/lib/commonjs/components/{ChatKit → KeyboardChatScrollView}/types.js +0 -0
  213. /package/lib/module/components/{ChatKit → KeyboardChatScrollView}/hooks.js +0 -0
  214. /package/lib/module/components/{ChatKit → KeyboardChatScrollView}/types.js +0 -0
package/README.md CHANGED
@@ -19,6 +19,7 @@ A universal keyboard handling solution for React Native — lightweight, fully c
19
19
  - 🌐 Display anything over the keyboard (without dismissing it) using `OverKeyboardView`
20
20
  - 🎨 Match keyboard background with `KeyboardBackgroundView`
21
21
  - 🧩 Extend keyboard with custom buttons/UI via `KeyboardExtender`
22
+ - 💬 Build chat interfaces (messenger and 🤖 AI chats) easily with `KeyboardChatScrollView`
22
23
  - 📝 Easy retrieval of focused input info
23
24
  - 🧭 Compatible with any navigation library
24
25
  - ✨ More coming soon... stay tuned! 😊
@@ -60,5 +60,6 @@ class KeyboardControllerPackage : BaseReactPackage() {
60
60
  OverKeyboardViewManager(),
61
61
  KeyboardBackgroundViewManager(),
62
62
  ClippingScrollViewDecoratorViewManager(),
63
+ KeyboardToolbarGroupViewManager(),
63
64
  )
64
65
  }
@@ -27,4 +27,18 @@ class ClippingScrollViewDecoratorViewManager :
27
27
  ) {
28
28
  view?.setContentInsetBottom(value)
29
29
  }
30
+
31
+ override fun setContentInsetTop(
32
+ view: ClippingScrollViewDecoratorView?,
33
+ value: Double,
34
+ ) {
35
+ view?.setContentInsetTop(value)
36
+ }
37
+
38
+ override fun setApplyWorkaroundForContentInsetHitTestBug(
39
+ view: ClippingScrollViewDecoratorView?,
40
+ value: Boolean,
41
+ ) {
42
+ view?.setApplyWorkaroundForContentInsetHitTestBug(value)
43
+ }
30
44
  }
@@ -1,5 +1,6 @@
1
1
  package com.reactnativekeyboardcontroller
2
2
 
3
+ import com.facebook.react.bridge.Promise
3
4
  import com.facebook.react.bridge.ReactApplicationContext
4
5
  import com.reactnativekeyboardcontroller.modules.KeyboardControllerModuleImpl
5
6
 
@@ -33,6 +34,13 @@ class KeyboardControllerModule(
33
34
  module.setFocusTo(direction)
34
35
  }
35
36
 
37
+ override fun viewPositionInWindow(
38
+ viewTag: Double,
39
+ promise: Promise,
40
+ ) {
41
+ module.viewPositionInWindow(viewTag, promise)
42
+ }
43
+
36
44
  override fun addListener(eventName: String?) {
37
45
  // Required for RN built-in Event Emitter Calls.
38
46
  }
@@ -0,0 +1,23 @@
1
+ package com.reactnativekeyboardcontroller
2
+
3
+ import com.facebook.react.uimanager.ThemedReactContext
4
+ import com.facebook.react.uimanager.ViewGroupManager
5
+ import com.facebook.react.uimanager.ViewManagerDelegate
6
+ import com.facebook.react.viewmanagers.KeyboardToolbarGroupViewManagerDelegate
7
+ import com.facebook.react.viewmanagers.KeyboardToolbarGroupViewManagerInterface
8
+ import com.reactnativekeyboardcontroller.managers.KeyboardToolbarGroupViewManagerImpl
9
+ import com.reactnativekeyboardcontroller.views.KeyboardToolbarGroupReactViewGroup
10
+
11
+ class KeyboardToolbarGroupViewManager :
12
+ ViewGroupManager<KeyboardToolbarGroupReactViewGroup>(),
13
+ KeyboardToolbarGroupViewManagerInterface<KeyboardToolbarGroupReactViewGroup> {
14
+ private val manager = KeyboardToolbarGroupViewManagerImpl()
15
+ private val mDelegate = KeyboardToolbarGroupViewManagerDelegate(this)
16
+
17
+ override fun getDelegate(): ViewManagerDelegate<KeyboardToolbarGroupReactViewGroup> = mDelegate
18
+
19
+ override fun getName(): String = KeyboardToolbarGroupViewManagerImpl.NAME
20
+
21
+ override fun createViewInstance(context: ThemedReactContext): KeyboardToolbarGroupReactViewGroup =
22
+ manager.createViewInstance(context)
23
+ }
@@ -3,6 +3,18 @@ package com.reactnativekeyboardcontroller.extensions
3
3
  import android.view.View
4
4
  import android.view.ViewGroup
5
5
  import com.facebook.react.bridge.ReactContext
6
+ import com.facebook.react.uimanager.UIManagerHelper
7
+ import com.facebook.react.uimanager.common.UIManagerType
8
+ import com.facebook.react.uimanager.events.EventDispatcher
9
+ import com.reactnativekeyboardcontroller.BuildConfig
10
+
11
+ private val archType = if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) UIManagerType.FABRIC else UIManagerType.DEFAULT
12
+
13
+ val ReactContext.uiManager
14
+ get() = UIManagerHelper.getUIManager(this, archType)
15
+
16
+ val ReactContext.eventDispatcher: EventDispatcher?
17
+ get() = UIManagerHelper.getEventDispatcher(this, archType)
6
18
 
7
19
  val ReactContext.rootView: View?
8
20
  get() =
@@ -120,7 +120,8 @@ class FocusedInputObserver(
120
120
  selectionSubscription = newFocus.addOnSelectionChangedListener(selectionListener)
121
121
  FocusedInputHolder.set(newFocus)
122
122
 
123
- val allInputFields = ViewHierarchyNavigator.getAllInputFields(context?.rootView)
123
+ val groupAncestor = ViewHierarchyNavigator.findGroupAncestor(newFocus)
124
+ val allInputFields = ViewHierarchyNavigator.getAllInputFields(groupAncestor ?: context?.rootView)
124
125
  val currentIndex = allInputFields.indexOf(newFocus)
125
126
 
126
127
  context.emitEvent(
@@ -18,6 +18,7 @@ class WindowDimensionListener(
18
18
  ) {
19
19
  private var lastDispatchedDimensions = Dimensions(0.0, 0.0)
20
20
  private var layoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null
21
+ private var attachedContent: ViewGroup? = null
21
22
 
22
23
  public fun attachListener() {
23
24
  // attach to content view only once per app instance
@@ -25,6 +26,7 @@ class WindowDimensionListener(
25
26
  listenerID = context.hashCode()
26
27
 
27
28
  val content = context.content
29
+ attachedContent = content
28
30
 
29
31
  updateWindowDimensions(content)
30
32
 
@@ -38,7 +40,9 @@ class WindowDimensionListener(
38
40
  }
39
41
 
40
42
  public fun detachListener() {
41
- context?.content?.viewTreeObserver?.removeOnGlobalLayoutListener(layoutListener)
43
+ attachedContent?.viewTreeObserver?.removeOnGlobalLayoutListener(layoutListener)
44
+ attachedContent = null
45
+ layoutListener = null
42
46
  }
43
47
 
44
48
  private fun updateWindowDimensions(content: ViewGroup?) {
@@ -0,0 +1,13 @@
1
+ package com.reactnativekeyboardcontroller.managers
2
+
3
+ import com.facebook.react.uimanager.ThemedReactContext
4
+ import com.reactnativekeyboardcontroller.views.KeyboardToolbarGroupReactViewGroup
5
+
6
+ class KeyboardToolbarGroupViewManagerImpl {
7
+ fun createViewInstance(reactContext: ThemedReactContext): KeyboardToolbarGroupReactViewGroup =
8
+ KeyboardToolbarGroupReactViewGroup(reactContext)
9
+
10
+ companion object {
11
+ const val NAME = "KeyboardToolbarGroupView"
12
+ }
13
+ }
@@ -4,15 +4,14 @@ import android.view.ViewGroup
4
4
  import android.view.WindowManager
5
5
  import androidx.core.view.ViewCompat
6
6
  import com.facebook.react.uimanager.ThemedReactContext
7
- import com.facebook.react.uimanager.UIManagerHelper
8
- import com.facebook.react.uimanager.common.UIManagerType
9
7
  import com.facebook.react.uimanager.events.Event
10
8
  import com.facebook.react.uimanager.events.EventDispatcherListener
11
9
  import com.facebook.react.views.modal.ReactModalHostView
12
10
  import com.facebook.react.views.view.ReactViewGroup
13
- import com.reactnativekeyboardcontroller.BuildConfig
14
11
  import com.reactnativekeyboardcontroller.constants.Keyboard
12
+ import com.reactnativekeyboardcontroller.extensions.eventDispatcher
15
13
  import com.reactnativekeyboardcontroller.extensions.removeSelf
14
+ import com.reactnativekeyboardcontroller.extensions.uiManager
16
15
  import com.reactnativekeyboardcontroller.listeners.KeyboardAnimationCallback
17
16
  import com.reactnativekeyboardcontroller.listeners.KeyboardAnimationCallbackConfig
18
17
  import com.reactnativekeyboardcontroller.log.Logger
@@ -26,9 +25,8 @@ class ModalAttachedWatcher(
26
25
  private val config: KeyboardAnimationCallbackConfig,
27
26
  private var callback: () -> KeyboardAnimationCallback?,
28
27
  ) : EventDispatcherListener {
29
- private val archType = if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) UIManagerType.FABRIC else UIManagerType.DEFAULT
30
- private val uiManager = UIManagerHelper.getUIManager(reactContext.reactApplicationContext, archType)
31
- private val eventDispatcher = UIManagerHelper.getEventDispatcher(reactContext.reactApplicationContext, archType)
28
+ private val uiManager = reactContext.uiManager
29
+ private val eventDispatcher = reactContext.eventDispatcher
32
30
 
33
31
  override fun onEventDispatch(event: Event<*>) {
34
32
  if (event.eventName != MODAL_SHOW_EVENT) {
@@ -5,8 +5,13 @@ import android.os.Build
5
5
  import android.view.View
6
6
  import android.view.WindowManager
7
7
  import android.view.inputmethod.InputMethodManager
8
+ import com.facebook.react.bridge.Arguments
9
+ import com.facebook.react.bridge.Promise
8
10
  import com.facebook.react.bridge.ReactApplicationContext
9
11
  import com.facebook.react.bridge.UiThreadUtil
12
+ import com.reactnativekeyboardcontroller.extensions.dp
13
+ import com.reactnativekeyboardcontroller.extensions.screenLocation
14
+ import com.reactnativekeyboardcontroller.extensions.uiManager
10
15
  import com.reactnativekeyboardcontroller.interactive.KeyboardAnimationController
11
16
  import com.reactnativekeyboardcontroller.traversal.FocusedInputHolder
12
17
  import com.reactnativekeyboardcontroller.traversal.ViewHierarchyNavigator
@@ -14,6 +19,7 @@ import com.reactnativekeyboardcontroller.traversal.ViewHierarchyNavigator
14
19
  class KeyboardControllerModuleImpl(
15
20
  private val mReactContext: ReactApplicationContext,
16
21
  ) {
22
+ private val uiManager = mReactContext.uiManager
17
23
  private val controller = KeyboardAnimationController()
18
24
  private val mDefaultMode: Int = getCurrentMode()
19
25
 
@@ -77,6 +83,26 @@ class KeyboardControllerModuleImpl(
77
83
  }
78
84
  }
79
85
 
86
+ fun viewPositionInWindow(
87
+ viewTag: Double,
88
+ promise: Promise,
89
+ ) {
90
+ UiThreadUtil.runOnUiThread {
91
+ val view = uiManager?.resolveView(viewTag.toInt())
92
+ if (view == null) {
93
+ promise.reject("E_VIEW_NOT_FOUND", "Could not find view for tag")
94
+ return@runOnUiThread
95
+ }
96
+ val location = view.screenLocation
97
+ val map = Arguments.createMap()
98
+ map.putDouble("x", location[0].toFloat().dp)
99
+ map.putDouble("y", location[1].toFloat().dp)
100
+ map.putDouble("width", view.width.toFloat().dp)
101
+ map.putDouble("height", view.height.toFloat().dp)
102
+ promise.resolve(map)
103
+ }
104
+ }
105
+
80
106
  private fun setSoftInputMode(mode: Int) {
81
107
  UiThreadUtil.runOnUiThread {
82
108
  if (getCurrentMode() != mode) {
@@ -5,6 +5,7 @@ import android.view.ViewGroup
5
5
  import android.widget.EditText
6
6
  import com.facebook.react.bridge.UiThreadUtil
7
7
  import com.reactnativekeyboardcontroller.extensions.focus
8
+ import com.reactnativekeyboardcontroller.views.KeyboardToolbarGroupReactViewGroup
8
9
 
9
10
  object ViewHierarchyNavigator {
10
11
  fun setFocusTo(
@@ -25,19 +26,40 @@ object ViewHierarchyNavigator {
25
26
  fun findEditTexts(view: View?) {
26
27
  if (isValidTextInput(view)) {
27
28
  editTexts.add(view as EditText)
28
- } else if (view is ViewGroup) {
29
+ } else if (view is ViewGroup && view !is KeyboardToolbarGroupReactViewGroup) {
29
30
  for (i in 0 until view.childCount) {
30
31
  findEditTexts(view.getChildAt(i))
31
32
  }
32
33
  }
33
34
  }
34
35
 
35
- // Start the search with the provided viewGroup
36
- findEditTexts(viewGroup)
36
+ // If the root is a group itself, search within it (for group-scoped queries)
37
+ if (viewGroup is KeyboardToolbarGroupReactViewGroup) {
38
+ for (i in 0 until viewGroup.childCount) {
39
+ findEditTexts(viewGroup.getChildAt(i))
40
+ }
41
+ } else {
42
+ findEditTexts(viewGroup)
43
+ }
37
44
 
38
45
  return editTexts
39
46
  }
40
47
 
48
+ /**
49
+ * Finds the closest [KeyboardToolbarGroupReactViewGroup] ancestor of the given view.
50
+ * Returns null if the view is not inside any group.
51
+ */
52
+ fun findGroupAncestor(view: View?): KeyboardToolbarGroupReactViewGroup? {
53
+ var current = view?.parent
54
+ while (current != null) {
55
+ if (current is KeyboardToolbarGroupReactViewGroup) {
56
+ return current
57
+ }
58
+ current = current.parent
59
+ }
60
+ return null
61
+ }
62
+
41
63
  private fun findNextEditText(currentFocus: View): EditText? = findEditTextInDirection(currentFocus, 1)
42
64
 
43
65
  private fun findPreviousEditText(currentFocus: View): EditText? = findEditTextInDirection(currentFocus, -1)
@@ -64,6 +86,11 @@ object ViewHierarchyNavigator {
64
86
  i += direction
65
87
  }
66
88
 
89
+ // Don't navigate outside the group boundary
90
+ if (parentViewGroup is KeyboardToolbarGroupReactViewGroup) {
91
+ return null
92
+ }
93
+
67
94
  // Recurse to the parent's parent if no sibling EditText is found
68
95
  return findEditTextInDirection(parentViewGroup, direction)
69
96
  }
@@ -91,7 +118,7 @@ object ViewHierarchyNavigator {
91
118
 
92
119
  if (isValidTextInput(child)) {
93
120
  result = child as EditText
94
- } else if (child is ViewGroup) {
121
+ } else if (child is ViewGroup && child !is KeyboardToolbarGroupReactViewGroup) {
95
122
  // If the child is a ViewGroup, check its children recursively
96
123
  result = findEditTextInHierarchy(child, direction)
97
124
  }
@@ -1,6 +1,7 @@
1
1
  package com.reactnativekeyboardcontroller.views
2
2
 
3
3
  import android.annotation.SuppressLint
4
+ import android.view.ViewGroup
4
5
  import android.widget.ScrollView
5
6
  import com.facebook.react.uimanager.ThemedReactContext
6
7
  import com.facebook.react.views.view.ReactViewGroup
@@ -11,6 +12,8 @@ class ClippingScrollViewDecoratorView(
11
12
  val reactContext: ThemedReactContext,
12
13
  ) : ReactViewGroup(reactContext) {
13
14
  private var insetBottom = 0.0
15
+ private var insetTop = 0.0
16
+ private var appliedTopInsetPx = 0
14
17
 
15
18
  override fun onAttachedToWindow() {
16
19
  super.onAttachedToWindow()
@@ -23,15 +26,44 @@ class ClippingScrollViewDecoratorView(
23
26
  decorateScrollView()
24
27
  }
25
28
 
29
+ fun setContentInsetTop(value: Double) {
30
+ insetTop = value
31
+ decorateScrollView()
32
+ }
33
+
34
+ @Suppress("detekt:UnusedParameter")
35
+ fun setApplyWorkaroundForContentInsetHitTestBug(value: Boolean) {
36
+ // iOS-only workaround; no-op on Android
37
+ }
38
+
26
39
  private fun decorateScrollView() {
27
40
  val scrollView = getChildAt(0) as? ScrollView ?: return
28
41
 
29
42
  scrollView.clipToPadding = false
43
+
44
+ val newTopInsetPx = insetTop.toFloat().px.toInt()
45
+
46
+ // Translate the content view as a whole — this keeps FlatList's
47
+ // virtualizer calculations correct (it reads layout positions,
48
+ // not translationY).
49
+ val contentView = scrollView.getChildAt(0) as? ViewGroup ?: return
50
+ (contentView.getChildAt(0) as? ViewGroup)?.translationY = newTopInsetPx.toFloat()
51
+
30
52
  scrollView.setPadding(
31
53
  scrollView.paddingLeft,
32
54
  scrollView.paddingTop,
33
55
  scrollView.paddingRight,
34
- insetBottom.toFloat().px.toInt(),
56
+ // pass accumulated value — visually both top and bottom insets
57
+ // extend the scroll range via bottom padding
58
+ (insetBottom + insetTop).toFloat().px.toInt(),
35
59
  )
60
+
61
+ // scroll by the delta to keep content visually in place
62
+ val delta = newTopInsetPx - appliedTopInsetPx
63
+ if (delta != 0) {
64
+ scrollView.scrollBy(0, delta)
65
+ }
66
+
67
+ appliedTopInsetPx = newTopInsetPx
36
68
  }
37
69
  }
@@ -0,0 +1,13 @@
1
+ package com.reactnativekeyboardcontroller.views
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.Context
5
+ import com.facebook.react.uimanager.ThemedReactContext
6
+ import com.facebook.react.views.view.ReactViewGroup
7
+
8
+ @SuppressLint("ViewConstructor")
9
+ class KeyboardToolbarGroupReactViewGroup : ReactViewGroup {
10
+ constructor(reactContext: ThemedReactContext) : super(reactContext)
11
+ internal constructor(context: Context) : super(context)
12
+ // semantic view used in KeyboardToolbar traverse algorithm
13
+ }
@@ -14,6 +14,8 @@
14
14
  #include <react/renderer/components/RNKC/RNKCKeyboardGestureAreaComponentDescriptor.h>
15
15
  #include <react/renderer/components/RNKC/RNKCOverKeyboardViewComponentDescriptor.h>
16
16
  #include <react/renderer/components/RNKC/RNKCKeyboardBackgroundViewComponentDescriptor.h>
17
+ #include <react/renderer/components/RNKC/RNKCClippingScrollViewDecoratorViewComponentDescriptor.h>
18
+ #include <react/renderer/components/RNKC/RNKCKeyboardToolbarGroupViewComponentDescriptor.h>
17
19
 
18
20
  #include <memory>
19
21
  #include <string>
@@ -21,4 +21,20 @@ class ClippingScrollViewDecoratorViewManager : ViewGroupManager<ClippingScrollVi
21
21
  ) {
22
22
  view.setContentInsetBottom(value)
23
23
  }
24
+
25
+ @ReactProp(name = "contentInsetTop")
26
+ fun setContentInsetTop(
27
+ view: ClippingScrollViewDecoratorView,
28
+ value: Double,
29
+ ) {
30
+ view.setContentInsetTop(value)
31
+ }
32
+
33
+ @ReactProp(name = "applyWorkaroundForContentInsetHitTestBug")
34
+ fun setApplyWorkaroundForContentInsetHitTestBug(
35
+ view: ClippingScrollViewDecoratorView,
36
+ value: Boolean,
37
+ ) {
38
+ view.setApplyWorkaroundForContentInsetHitTestBug(value)
39
+ }
24
40
  }
@@ -1,5 +1,6 @@
1
1
  package com.reactnativekeyboardcontroller
2
2
 
3
+ import com.facebook.react.bridge.Promise
3
4
  import com.facebook.react.bridge.ReactApplicationContext
4
5
  import com.facebook.react.bridge.ReactContextBaseJavaModule
5
6
  import com.facebook.react.bridge.ReactMethod
@@ -40,6 +41,14 @@ class KeyboardControllerModule(
40
41
  module.setFocusTo(direction)
41
42
  }
42
43
 
44
+ @ReactMethod
45
+ fun viewPositionInWindow(
46
+ viewTag: Double,
47
+ promise: Promise,
48
+ ) {
49
+ module.viewPositionInWindow(viewTag, promise)
50
+ }
51
+
43
52
  @Suppress("detekt:UnusedParameter")
44
53
  @ReactMethod
45
54
  fun addListener(eventName: String?) {
@@ -0,0 +1,15 @@
1
+ package com.reactnativekeyboardcontroller
2
+
3
+ import com.facebook.react.uimanager.ThemedReactContext
4
+ import com.facebook.react.views.view.ReactViewManager
5
+ import com.reactnativekeyboardcontroller.managers.KeyboardToolbarGroupViewManagerImpl
6
+ import com.reactnativekeyboardcontroller.views.KeyboardToolbarGroupReactViewGroup
7
+
8
+ class KeyboardToolbarGroupViewManager : ReactViewManager() {
9
+ private val manager = KeyboardToolbarGroupViewManagerImpl()
10
+
11
+ override fun getName(): String = KeyboardToolbarGroupViewManagerImpl.NAME
12
+
13
+ override fun createViewInstance(reactContext: ThemedReactContext): KeyboardToolbarGroupReactViewGroup =
14
+ manager.createViewInstance(reactContext)
15
+ }
@@ -60,5 +60,7 @@ class KeyboardControllerPackage : TurboReactPackage() {
60
60
  KeyboardGestureAreaViewManager(),
61
61
  OverKeyboardViewManager(),
62
62
  KeyboardBackgroundViewManager(),
63
+ ClippingScrollViewDecoratorViewManager(),
64
+ KeyboardToolbarGroupViewManager(),
63
65
  )
64
66
  }
@@ -0,0 +1,27 @@
1
+ //
2
+ // RNKCClippingScrollViewDecoratorViewComponentDescriptor.h
3
+ // Pods
4
+ //
5
+ // Created by Kiryl Ziusko on 03/03/2025.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include "RNKCClippingScrollViewDecoratorViewShadowNode.h"
11
+
12
+ #include <react/debug/react_native_assert.h>
13
+ #include <react/renderer/components/RNKC/Props.h>
14
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
15
+
16
+ namespace facebook::react {
17
+ class ClippingScrollViewDecoratorViewComponentDescriptor final
18
+ : public ConcreteComponentDescriptor<ClippingScrollViewDecoratorViewShadowNode> {
19
+ public:
20
+ using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
21
+ void adopt(ShadowNode &shadowNode) const override {
22
+ react_native_assert(dynamic_cast<ClippingScrollViewDecoratorViewShadowNode *>(&shadowNode));
23
+ ConcreteComponentDescriptor::adopt(shadowNode);
24
+ }
25
+ };
26
+
27
+ } // namespace facebook::react
@@ -0,0 +1,14 @@
1
+ //
2
+ // RNKCClippingScrollViewDecoratorViewShadowNode.cpp
3
+ // Pods
4
+ //
5
+ // Created by Kiryl Ziusko on 03/03/2025.
6
+ //
7
+
8
+ #include "RNKCClippingScrollViewDecoratorViewShadowNode.h"
9
+
10
+ namespace facebook::react {
11
+
12
+ extern const char ClippingScrollViewDecoratorViewComponentName[] = "ClippingScrollViewDecoratorView";
13
+
14
+ } // namespace facebook::react
@@ -0,0 +1,30 @@
1
+ //
2
+ // RNKCClippingScrollViewDecoratorViewShadowNode.h
3
+ // Pods
4
+ //
5
+ // Created by Kiryl Ziusko on 03/03/2025.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include "RNKCClippingScrollViewDecoratorViewState.h"
11
+
12
+ #include <react/renderer/components/RNKC/EventEmitters.h>
13
+ #include <react/renderer/components/RNKC/Props.h>
14
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
15
+ #include <jsi/jsi.h>
16
+
17
+ namespace facebook::react {
18
+
19
+ JSI_EXPORT extern const char ClippingScrollViewDecoratorViewComponentName[];
20
+
21
+ /*
22
+ * `ShadowNode` for <ClippingScrollViewDecoratorView> component.
23
+ */
24
+ using ClippingScrollViewDecoratorViewShadowNode = ConcreteViewShadowNode<
25
+ ClippingScrollViewDecoratorViewComponentName,
26
+ ClippingScrollViewDecoratorViewProps,
27
+ ClippingScrollViewDecoratorViewEventEmitter,
28
+ ClippingScrollViewDecoratorViewState>;
29
+
30
+ } // namespace facebook::react
@@ -0,0 +1,28 @@
1
+ //
2
+ // RNKCClippingScrollViewDecoratorViewState.h
3
+ // Pods
4
+ //
5
+ // Created by Kiryl Ziusko on 03/03/2025.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #ifdef ANDROID
11
+ #include <folly/dynamic.h>
12
+ #endif
13
+
14
+ namespace facebook::react {
15
+
16
+ class ClippingScrollViewDecoratorViewState {
17
+ public:
18
+ ClippingScrollViewDecoratorViewState() = default;
19
+
20
+ #ifdef ANDROID
21
+ ClippingScrollViewDecoratorViewState(ClippingScrollViewDecoratorViewState const &previousState, folly::dynamic data) {}
22
+ folly::dynamic getDynamic() const {
23
+ return {};
24
+ }
25
+ #endif
26
+ };
27
+
28
+ } // namespace facebook::react
@@ -0,0 +1,20 @@
1
+ #pragma once
2
+
3
+ #include "RNKCKeyboardToolbarGroupViewShadowNode.h"
4
+
5
+ #include <react/debug/react_native_assert.h>
6
+ #include <react/renderer/components/RNKC/Props.h>
7
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
8
+
9
+ namespace facebook::react {
10
+ class KeyboardToolbarGroupViewComponentDescriptor final
11
+ : public ConcreteComponentDescriptor<KeyboardToolbarGroupViewShadowNode> {
12
+ public:
13
+ using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
14
+ void adopt(ShadowNode &shadowNode) const override {
15
+ react_native_assert(dynamic_cast<KeyboardToolbarGroupViewShadowNode *>(&shadowNode));
16
+ ConcreteComponentDescriptor::adopt(shadowNode);
17
+ }
18
+ };
19
+
20
+ } // namespace facebook::react
@@ -0,0 +1,7 @@
1
+ #include "RNKCKeyboardToolbarGroupViewShadowNode.h"
2
+
3
+ namespace facebook::react {
4
+
5
+ extern const char KeyboardToolbarGroupViewComponentName[] = "KeyboardToolbarGroupView";
6
+
7
+ } // namespace facebook::react
@@ -0,0 +1,23 @@
1
+ #pragma once
2
+
3
+ #include "RNKCKeyboardToolbarGroupViewState.h"
4
+
5
+ #include <react/renderer/components/RNKC/EventEmitters.h>
6
+ #include <react/renderer/components/RNKC/Props.h>
7
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
8
+ #include <jsi/jsi.h>
9
+
10
+ namespace facebook::react {
11
+
12
+ JSI_EXPORT extern const char KeyboardToolbarGroupViewComponentName[];
13
+
14
+ /*
15
+ * `ShadowNode` for <KeyboardToolbarGroupView> component.
16
+ */
17
+ using KeyboardToolbarGroupViewShadowNode = ConcreteViewShadowNode<
18
+ KeyboardToolbarGroupViewComponentName,
19
+ KeyboardToolbarGroupViewProps,
20
+ KeyboardToolbarGroupViewEventEmitter,
21
+ KeyboardToolbarGroupViewState>;
22
+
23
+ } // namespace facebook::react
@@ -0,0 +1,21 @@
1
+ #pragma once
2
+
3
+ #ifdef ANDROID
4
+ #include <folly/dynamic.h>
5
+ #endif
6
+
7
+ namespace facebook::react {
8
+
9
+ class KeyboardToolbarGroupViewState {
10
+ public:
11
+ KeyboardToolbarGroupViewState() = default;
12
+
13
+ #ifdef ANDROID
14
+ KeyboardToolbarGroupViewState(KeyboardToolbarGroupViewState const &previousState, folly::dynamic data) {}
15
+ folly::dynamic getDynamic() const {
16
+ return {};
17
+ }
18
+ #endif
19
+ };
20
+
21
+ } // namespace facebook::react