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
@@ -32,7 +32,7 @@ public class KeyboardMovementObserver: NSObject {
32
32
 
33
33
  private var _windowsCount: Int = 0
34
34
  private var prevKeyboardPosition = 0.0
35
- private var displayLink: CADisplayLink?
35
+ private var displayLink: CADisplayLink!
36
36
  private var interactiveKeyboardObserver: NSKeyValueObservation?
37
37
  private var isMounted = false
38
38
  // state variables
@@ -57,6 +57,18 @@ public class KeyboardMovementObserver: NSObject {
57
57
  self.onNotify = onNotify
58
58
  self.onRequestAnimation = onRequestAnimation
59
59
  self.onCancelAnimation = onCancelAnimation
60
+
61
+ super.init()
62
+
63
+ displayLink = CADisplayLink(target: self, selector: #selector(updateKeyboardFrame))
64
+ displayLink.preferredFramesPerSecond = 120 // will fallback to 60 fps for devices without Pro Motion display
65
+ displayLink.add(to: .main, forMode: .common)
66
+ displayLink.isPaused = true
67
+ }
68
+
69
+ deinit {
70
+ displayLink.invalidate()
71
+ displayLink = nil
60
72
  }
61
73
 
62
74
  @objc public func mount() {
@@ -108,8 +120,11 @@ public class KeyboardMovementObserver: NSObject {
108
120
  }
109
121
 
110
122
  private func keyboardDidMoveInteractively(changeValue: CGPoint) {
123
+ if UIResponder.isKeyboardPreloading {
124
+ return
125
+ }
111
126
  // if we are currently animating keyboard -> we need to ignore values from KVO
112
- if displayLink != nil {
127
+ if !displayLink.isPaused {
113
128
  return
114
129
  }
115
130
  // if keyboard height is not equal to its bounds - we can ignore
@@ -153,7 +168,7 @@ public class KeyboardMovementObserver: NSObject {
153
168
  }
154
169
 
155
170
  @objc func keyboardWillAppear(_ notification: Notification) {
156
- guard !KeyboardEventsIgnorer.shared.shouldIgnore else { return }
171
+ guard !KeyboardEventsIgnorer.shared.shouldIgnore, !UIResponder.isKeyboardPreloading else { return }
157
172
 
158
173
  let (duration, frame) = notification.keyboardMetaData()
159
174
  if let keyboardFrame = frame {
@@ -173,6 +188,7 @@ public class KeyboardMovementObserver: NSObject {
173
188
  }
174
189
 
175
190
  @objc func keyboardWillDisappear(_ notification: Notification) {
191
+ guard !UIResponder.isKeyboardPreloading else { return }
176
192
  let (duration, _) = notification.keyboardMetaData()
177
193
  tag = UIResponder.current.reactViewTag
178
194
  self.duration = duration
@@ -187,6 +203,7 @@ public class KeyboardMovementObserver: NSObject {
187
203
  }
188
204
 
189
205
  @objc func keyboardDidAppear(_ notification: Notification) {
206
+ guard !UIResponder.isKeyboardPreloading else { return }
190
207
  let timestamp = Date.currentTimeStamp
191
208
  let (duration, frame) = notification.keyboardMetaData()
192
209
  if let keyboardFrame = frame {
@@ -217,6 +234,7 @@ public class KeyboardMovementObserver: NSObject {
217
234
  }
218
235
 
219
236
  @objc func keyboardDidDisappear(_ notification: Notification) {
237
+ guard !UIResponder.isKeyboardPreloading else { return }
220
238
  let (duration, _) = notification.keyboardMetaData()
221
239
  tag = UIResponder.current.reactViewTag
222
240
 
@@ -232,18 +250,15 @@ public class KeyboardMovementObserver: NSObject {
232
250
  // sometimes `will` events can be called multiple times.
233
251
  // To avoid double re-creation of listener we are adding this condition
234
252
  // (if active link is present, then no need to re-setup a listener)
235
- if displayLink != nil {
253
+ if !displayLink.isPaused {
236
254
  return
237
255
  }
238
256
 
239
- displayLink = CADisplayLink(target: self, selector: #selector(updateKeyboardFrame))
240
- displayLink?.preferredFramesPerSecond = 120 // will fallback to 60 fps for devices without Pro Motion display
241
- displayLink?.add(to: .main, forMode: .common)
257
+ displayLink.isPaused = false
242
258
  }
243
259
 
244
260
  @objc func removeKeyboardWatcher() {
245
- displayLink?.invalidate()
246
- displayLink = nil
261
+ displayLink.isPaused = true
247
262
  }
248
263
 
249
264
  func initializeAnimation(fromValue: Double, toValue: Double) {
@@ -30,3 +30,25 @@ extension UITextView: TextInput {
30
30
  becomeFirstResponder()
31
31
  }
32
32
  }
33
+
34
+ extension TextInput {
35
+ var keyboardAppearanceValue: String {
36
+ switch keyboardAppearance {
37
+ case .dark:
38
+ return "dark"
39
+ case .light:
40
+ return "light"
41
+ case .default:
42
+ switch traitCollection.userInterfaceStyle {
43
+ case .dark:
44
+ return "dark"
45
+ case .light, .unspecified:
46
+ return "light"
47
+ @unknown default:
48
+ return "light"
49
+ }
50
+ @unknown default:
51
+ return "light"
52
+ }
53
+ }
54
+ }
@@ -72,6 +72,9 @@ extension UIResponder {
72
72
 
73
73
  // Postpone execution of the original resignFirstResponder
74
74
  DispatchQueue.main.asyncAfter(deadline: .now() + UIUtils.nextFrame) {
75
+ NotificationCenter.default.post(
76
+ name: .shouldIgnoreKeyboardEvents, object: nil, userInfo: ["ignore": false]
77
+ )
75
78
  (self as? TextInput)?.inputAccessoryView = nil
76
79
  KeyboardAreaExtender.shared.remove()
77
80
  _ = self.callOriginalResignFirstResponder(originalResignSelector)
@@ -10,15 +10,18 @@ import Foundation
10
10
  import UIKit
11
11
 
12
12
  enum KeyboardView {
13
+ private static let windowPrefix = "<UITextEffectsWindow"
14
+ private static let containerPrefixes = ["<UIInputSetContainerView", "<UITrackingWindowView"]
15
+ private static let hostPrefixes = ["<UIInputSetHostView", "<UIKeyboardItemContainerView"]
13
16
  // inspired by https://stackoverflow.com/questions/32598490/show-uiview-with-buttons-over-keyboard-like-in-skype-viber-messengers-swift-i
14
17
  static func find() -> UIView? {
15
18
  let windows = UIApplication.shared.windows
16
19
  for window in windows {
17
- if window.description.hasPrefix("<UITextEffectsWindow") {
20
+ if window.description.hasPrefix(windowPrefix) {
18
21
  for subview in window.subviews {
19
- if subview.description.hasPrefix("<UIInputSetContainerView") {
22
+ if subview.description.hasAnyPrefix(containerPrefixes) {
20
23
  for hostView in subview.subviews {
21
- if hostView.description.hasPrefix("<UIInputSetHostView"), hostView.frame.height != 0 {
24
+ if hostView.description.hasAnyPrefix(hostPrefixes), hostView.frame.height != 0 {
22
25
  return hostView
23
26
  }
24
27
  }
@@ -0,0 +1,29 @@
1
+ //
2
+ // KeyboardBackgroundViewManager.h
3
+ // Pods
4
+ //
5
+ // Created by Kiryl Ziusko on 21/04/2025.
6
+ //
7
+
8
+ #ifdef RCT_NEW_ARCH_ENABLED
9
+ #import <React/RCTViewComponentView.h>
10
+ #else
11
+ #import <React/RCTBridge.h>
12
+ #endif
13
+ #import <React/RCTViewManager.h>
14
+ #import <UIKit/UIKit.h>
15
+
16
+ @interface KeyboardBackgroundViewManager : RCTViewManager
17
+ @end
18
+
19
+ @interface KeyboardBackgroundView :
20
+ #ifdef RCT_NEW_ARCH_ENABLED
21
+ RCTViewComponentView
22
+ #else
23
+ UIView
24
+
25
+ - (instancetype)initWithBridge:(RCTBridge *)bridge;
26
+
27
+ #endif
28
+
29
+ @end
@@ -0,0 +1,168 @@
1
+ //
2
+ // KeyboardBackgroundViewManager.mm
3
+ // Pods
4
+ //
5
+ // Created by Kiryl Ziusko on 21/04/2025.
6
+ //
7
+
8
+ #import "KeyboardBackgroundViewManager.h"
9
+
10
+ #if __has_include("react_native_keyboard_controller-Swift.h")
11
+ #import "react_native_keyboard_controller-Swift.h"
12
+ #else
13
+ #import <react_native_keyboard_controller/react_native_keyboard_controller-Swift.h>
14
+ #endif
15
+
16
+ #ifdef RCT_NEW_ARCH_ENABLED
17
+ #import <react/renderer/components/reactnativekeyboardcontroller/EventEmitters.h>
18
+ #import <react/renderer/components/reactnativekeyboardcontroller/Props.h>
19
+ #import <react/renderer/components/reactnativekeyboardcontroller/RCTComponentViewHelpers.h>
20
+ #import <react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardBackgroundViewComponentDescriptor.h>
21
+
22
+ #import "RCTFabricComponentsPlugins.h"
23
+ #endif
24
+
25
+ #import <React/RCTView.h>
26
+ #import <UIKit/UIKit.h>
27
+
28
+ #ifdef RCT_NEW_ARCH_ENABLED
29
+ using namespace facebook::react;
30
+ #endif
31
+
32
+ typedef NS_ENUM(NSInteger, KeyboardBackdropStyle) {
33
+ KeyboardBackdropStyleDark = 2030,
34
+ KeyboardBackdropStyleLight = 3901
35
+ };
36
+
37
+ @protocol KeyboardBackdropViewProtocol <NSObject>
38
+ @optional
39
+ - (instancetype)initWithFrame:(CGRect)frame style:(long long)style;
40
+ - (void)transitionToStyle:(long long)style;
41
+ @end
42
+
43
+ #pragma mark - Manager
44
+
45
+ @implementation KeyboardBackgroundViewManager
46
+
47
+ RCT_EXPORT_MODULE(KeyboardBackgroundViewManager)
48
+
49
+ + (BOOL)requiresMainQueueSetup
50
+ {
51
+ return NO;
52
+ }
53
+
54
+ #ifndef RCT_NEW_ARCH_ENABLED
55
+ - (UIView *)view
56
+ {
57
+ RCTView *containerView = [[RCTView alloc] initWithFrame:CGRectZero];
58
+ containerView.clipsToBounds = YES;
59
+
60
+ KeyboardBackgroundView *backgroundView =
61
+ [[KeyboardBackgroundView alloc] initWithFrame:containerView.bounds];
62
+ backgroundView.autoresizingMask =
63
+ UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
64
+ [containerView addSubview:backgroundView];
65
+
66
+ return containerView;
67
+ }
68
+ #endif
69
+
70
+ @end
71
+
72
+ #pragma mark - View
73
+
74
+ #ifdef RCT_NEW_ARCH_ENABLED
75
+ @interface KeyboardBackgroundView () <RCTKeyboardBackgroundViewViewProtocol>
76
+ #else
77
+ @interface KeyboardBackgroundView ()
78
+ #endif
79
+ @end
80
+
81
+ @implementation KeyboardBackgroundView {
82
+ UIVisualEffectView *_backdropView;
83
+ }
84
+
85
+ #ifdef RCT_NEW_ARCH_ENABLED
86
+ + (ComponentDescriptorProvider)componentDescriptorProvider
87
+ {
88
+ return concreteComponentDescriptorProvider<KeyboardBackgroundViewComponentDescriptor>();
89
+ }
90
+ #endif
91
+
92
+ // Needed because of this: https://github.com/facebook/react-native/pull/37274
93
+ + (void)load
94
+ {
95
+ [super load];
96
+ }
97
+
98
+ - (instancetype)initWithFrame:(CGRect)frame
99
+ {
100
+ self = [super initWithFrame:frame];
101
+ if (self) {
102
+ [self setupBackdropView];
103
+ }
104
+ self.clipsToBounds = YES;
105
+ return self;
106
+ }
107
+
108
+ - (void)setupBackdropView
109
+ {
110
+ Class BackdropClass = NSClassFromString(@"UIKBBackdropView");
111
+ if (BackdropClass) {
112
+ long long style = (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark)
113
+ ? KeyboardBackdropStyleDark
114
+ : KeyboardBackdropStyleLight;
115
+
116
+ id<KeyboardBackdropViewProtocol> backdrop =
117
+ (id<KeyboardBackdropViewProtocol>)[BackdropClass alloc];
118
+ backdrop = [backdrop initWithFrame:self.bounds style:style];
119
+
120
+ if ([backdrop isKindOfClass:[UIVisualEffectView class]]) {
121
+ _backdropView = (UIVisualEffectView *)backdrop;
122
+ _backdropView.layer.masksToBounds = YES;
123
+ _backdropView.autoresizingMask =
124
+ UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
125
+ _backdropView.frame = self.bounds;
126
+ [self addSubview:_backdropView];
127
+ }
128
+ } else {
129
+ NSLog(@"KeyboardBackdropView class not found");
130
+ }
131
+ }
132
+
133
+ // MARK: child management
134
+ #ifdef RCT_NEW_ARCH_ENABLED
135
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
136
+ index:(NSInteger)index
137
+ {
138
+ // preserve slot 0 for blur layer
139
+ [super mountChildComponentView:childComponentView index:index + 1];
140
+ }
141
+
142
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
143
+ index:(NSInteger)index
144
+ {
145
+ // preserve slot 0 for blur layer
146
+ [super unmountChildComponentView:childComponentView index:index + 1];
147
+ }
148
+ #endif
149
+
150
+ - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
151
+ {
152
+ [super traitCollectionDidChange:previousTraitCollection];
153
+
154
+ if (@available(iOS 12.0, *)) {
155
+ if ([previousTraitCollection
156
+ hasDifferentColorAppearanceComparedToTraitCollection:self.traitCollection]) {
157
+ long long style = (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark)
158
+ ? KeyboardBackdropStyleDark
159
+ : KeyboardBackdropStyleLight;
160
+
161
+ if ([_backdropView respondsToSelector:@selector(transitionToStyle:)]) {
162
+ [(id<KeyboardBackdropViewProtocol>)_backdropView transitionToStyle:style];
163
+ }
164
+ }
165
+ }
166
+ }
167
+
168
+ @end
@@ -0,0 +1,59 @@
1
+ //
2
+ // KeyboardExtenderContainerView.swift
3
+ // Pods
4
+ //
5
+ // Created by Kiryl Ziusko on 11/07/2025.
6
+ //
7
+
8
+ import UIKit
9
+
10
+ @objc
11
+ public class KeyboardExtenderContainerView: UIView {
12
+ @objc public static func create(frame: CGRect, contentView: UIView) -> UIView {
13
+ if #available(iOS 26.0, *) {
14
+ if let glassEffectClass = NSClassFromString("UIGlassEffect") as? UIVisualEffect.Type {
15
+ let paddingHorizontal = 20.0
16
+ let paddingBottom = 10.0
17
+ let isDark = FocusedInputHolder.shared.get()?.keyboardAppearanceValue == "dark"
18
+
19
+ let glassEffect = glassEffectClass.init()
20
+ let color = isDark ? UIColor.black.withAlphaComponent(0.3) : UIColor.gray.withAlphaComponent(0.3)
21
+ glassEffect.setValue(color, forKey: "tintColor")
22
+ glassEffect.setValue(true, forKey: "interactive")
23
+
24
+ // wrapper container will be full frame
25
+ let wrapperView = UIView(frame: frame)
26
+ wrapperView.backgroundColor = .clear
27
+
28
+ let innerWidth = frame.width - paddingHorizontal * 2
29
+ let innerHeight = frame.height
30
+
31
+ let visualEffectView = UIVisualEffectView(effect: glassEffect)
32
+ visualEffectView.overrideUserInterfaceStyle = isDark ? .dark : .light
33
+
34
+ visualEffectView.frame = CGRect(
35
+ x: paddingHorizontal,
36
+ y: -paddingBottom,
37
+ width: innerWidth,
38
+ height: innerHeight
39
+ )
40
+ contentView.frame = CGRect(
41
+ x: -paddingHorizontal,
42
+ y: 0,
43
+ width: innerWidth,
44
+ height: innerHeight
45
+ )
46
+
47
+ visualEffectView.contentView.addSubview(contentView)
48
+ wrapperView.addSubview(visualEffectView)
49
+
50
+ return wrapperView
51
+ }
52
+ }
53
+
54
+ let inputView = UIInputView(frame: frame, inputViewStyle: .keyboard)
55
+ contentView.frame = inputView.bounds
56
+ inputView.addSubview(contentView)
57
+ return inputView
58
+ }
59
+ }
@@ -0,0 +1,29 @@
1
+ //
2
+ // KeyboardExtenderManager.h
3
+ // KeyboardController
4
+ //
5
+ // Created by Kiryl Ziusko on 13.04.25.
6
+ // Copyright © 2025 Facebook. All rights reserved.
7
+ //
8
+ #ifdef RCT_NEW_ARCH_ENABLED
9
+ #import <React/RCTViewComponentView.h>
10
+ #else
11
+ #import <React/RCTBridge.h>
12
+ #endif
13
+ #import <React/RCTViewManager.h>
14
+ #import <UIKit/UIKit.h>
15
+
16
+ @interface KeyboardExtenderManager : RCTViewManager
17
+ @end
18
+
19
+ @interface KeyboardExtender :
20
+ #ifdef RCT_NEW_ARCH_ENABLED
21
+ RCTViewComponentView
22
+ #else
23
+ UIView
24
+
25
+ - (instancetype)initWithBridge:(RCTBridge *)bridge;
26
+
27
+ #endif
28
+ @property (nonatomic, assign) BOOL enabled;
29
+ @end