react-native-keyboard-controller 1.2.0 → 1.4.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 (107) hide show
  1. package/android/build.gradle +0 -40
  2. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardAnimationCallback.kt +8 -4
  3. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +44 -8
  4. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManagerImpl.kt +6 -3
  5. package/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt +2 -6
  6. package/ios/.swiftlint.yml +4 -0
  7. package/ios/KeyboardController.xcodeproj/project.pbxproj +2 -2
  8. package/ios/KeyboardControllerModule.mm +1 -1
  9. package/ios/KeyboardControllerView.mm +28 -10
  10. package/ios/KeyboardControllerViewManager.mm +2 -0
  11. package/ios/KeyboardControllerViewManager.swift +4 -1
  12. package/ios/KeyboardMoveEvent.h +1 -0
  13. package/ios/KeyboardMoveEvent.m +2 -1
  14. package/ios/KeyboardMovementObserver.swift +89 -4
  15. package/lib/commonjs/animated.js +44 -63
  16. package/lib/commonjs/animated.js.map +1 -1
  17. package/lib/commonjs/context.js +29 -0
  18. package/lib/commonjs/context.js.map +1 -0
  19. package/lib/commonjs/hooks.js +64 -0
  20. package/lib/commonjs/hooks.js.map +1 -0
  21. package/lib/commonjs/index.js +39 -0
  22. package/lib/commonjs/index.js.map +1 -1
  23. package/lib/commonjs/internal.js +91 -0
  24. package/lib/commonjs/internal.js.map +1 -0
  25. package/lib/commonjs/monkey-patch.js +3 -3
  26. package/lib/commonjs/monkey-patch.js.map +1 -1
  27. package/lib/commonjs/native.js +24 -21
  28. package/lib/commonjs/native.js.map +1 -1
  29. package/lib/commonjs/replicas.js +2 -2
  30. package/lib/commonjs/replicas.js.map +1 -1
  31. package/lib/commonjs/{KeyboardControllerViewNativeComponent.js → specs/KeyboardControllerViewNativeComponent.js} +0 -0
  32. package/lib/commonjs/{KeyboardControllerViewNativeComponent.js.map → specs/KeyboardControllerViewNativeComponent.js.map} +1 -1
  33. package/lib/commonjs/{NativeKeyboardController.js → specs/NativeKeyboardController.js} +0 -0
  34. package/lib/commonjs/{NativeKeyboardController.js.map → specs/NativeKeyboardController.js.map} +0 -0
  35. package/lib/commonjs/{NativeStatusBarManagerCompat.js → specs/NativeStatusBarManagerCompat.js} +0 -0
  36. package/lib/commonjs/{NativeStatusBarManagerCompat.js.map → specs/NativeStatusBarManagerCompat.js.map} +0 -0
  37. package/lib/commonjs/types.js +6 -0
  38. package/lib/commonjs/types.js.map +1 -0
  39. package/lib/commonjs/utils.js +11 -0
  40. package/lib/commonjs/utils.js.map +1 -0
  41. package/lib/module/animated.js +43 -55
  42. package/lib/module/animated.js.map +1 -1
  43. package/lib/module/context.js +19 -0
  44. package/lib/module/context.js.map +1 -0
  45. package/lib/module/hooks.js +39 -0
  46. package/lib/module/hooks.js.map +1 -0
  47. package/lib/module/index.js +3 -0
  48. package/lib/module/index.js.map +1 -1
  49. package/lib/module/internal.js +80 -0
  50. package/lib/module/internal.js.map +1 -0
  51. package/lib/module/monkey-patch.js +4 -3
  52. package/lib/module/monkey-patch.js.map +1 -1
  53. package/lib/module/native.js +23 -17
  54. package/lib/module/native.js.map +1 -1
  55. package/lib/module/replicas.js +1 -1
  56. package/lib/module/replicas.js.map +1 -1
  57. package/lib/module/{KeyboardControllerViewNativeComponent.js → specs/KeyboardControllerViewNativeComponent.js} +0 -0
  58. package/lib/module/{KeyboardControllerViewNativeComponent.js.map → specs/KeyboardControllerViewNativeComponent.js.map} +1 -1
  59. package/lib/module/{NativeKeyboardController.js → specs/NativeKeyboardController.js} +0 -0
  60. package/lib/module/{NativeKeyboardController.js.map → specs/NativeKeyboardController.js.map} +0 -0
  61. package/lib/module/{NativeStatusBarManagerCompat.js → specs/NativeStatusBarManagerCompat.js} +0 -0
  62. package/lib/module/{NativeStatusBarManagerCompat.js.map → specs/NativeStatusBarManagerCompat.js.map} +0 -0
  63. package/lib/module/types.js +2 -0
  64. package/lib/module/types.js.map +1 -0
  65. package/lib/module/utils.js +2 -0
  66. package/lib/module/utils.js.map +1 -0
  67. package/lib/typescript/animated.d.ts +1 -17
  68. package/lib/typescript/context.d.ts +18 -0
  69. package/lib/typescript/hooks.d.ts +8 -0
  70. package/lib/typescript/index.d.ts +3 -0
  71. package/lib/typescript/internal.d.ts +21 -0
  72. package/lib/typescript/native.d.ts +14 -26
  73. package/lib/typescript/{KeyboardControllerViewNativeComponent.d.ts → specs/KeyboardControllerViewNativeComponent.d.ts} +2 -0
  74. package/lib/typescript/{NativeKeyboardController.d.ts → specs/NativeKeyboardController.d.ts} +0 -0
  75. package/lib/typescript/{NativeStatusBarManagerCompat.d.ts → specs/NativeStatusBarManagerCompat.d.ts} +0 -0
  76. package/lib/typescript/types.d.ts +32 -0
  77. package/lib/typescript/utils.d.ts +1 -0
  78. package/package.json +17 -20
  79. package/react-native-keyboard-controller.podspec +2 -1
  80. package/src/animated.tsx +42 -78
  81. package/src/context.ts +31 -0
  82. package/src/hooks.ts +56 -0
  83. package/src/index.ts +3 -0
  84. package/src/internal.ts +87 -0
  85. package/src/{monkey-patch.tsx → monkey-patch.ts} +3 -6
  86. package/src/native.ts +37 -66
  87. package/src/replicas.ts +1 -1
  88. package/src/{KeyboardControllerViewNativeComponent.ts → specs/KeyboardControllerViewNativeComponent.ts} +4 -0
  89. package/src/{NativeKeyboardController.ts → specs/NativeKeyboardController.ts} +0 -0
  90. package/src/{NativeStatusBarManagerCompat.ts → specs/NativeStatusBarManagerCompat.ts} +0 -0
  91. package/src/types.ts +60 -0
  92. package/src/utils.ts +1 -0
  93. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  94. package/android/gradle/wrapper/gradle-wrapper.properties +0 -5
  95. package/android/gradlew +0 -185
  96. package/android/gradlew.bat +0 -89
  97. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerComponentsRegistry.kt +0 -31
  98. package/android/src/main/jni/Android.mk +0 -42
  99. package/android/src/main/jni/KeyboardControllerComponentsRegistry.cpp +0 -71
  100. package/android/src/main/jni/KeyboardControllerComponentsRegistry.h +0 -35
  101. package/android/src/main/jni/OnLoad.cpp +0 -9
  102. package/lib/commonjs/architecture.js +0 -13
  103. package/lib/commonjs/architecture.js.map +0 -1
  104. package/lib/module/architecture.js +0 -5
  105. package/lib/module/architecture.js.map +0 -1
  106. package/lib/typescript/architecture.d.ts +0 -2
  107. package/src/architecture.ts +0 -4
@@ -46,41 +46,11 @@ android {
46
46
  versionCode 1
47
47
  versionName "1.0"
48
48
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
49
- if (isNewArchitectureEnabled()) {
50
- var appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
51
- externalNativeBuild {
52
- ndkBuild {
53
- arguments "APP_PLATFORM=android-21",
54
- "APP_STL=c++_shared",
55
- "NDK_TOOLCHAIN_VERSION=clang",
56
- "GENERATED_SRC_DIR=${appProject.buildDir}/generated/source",
57
- "PROJECT_BUILD_DIR=${appProject.buildDir}",
58
- "REACT_ANDROID_DIR=${appProject.rootDir}/../node_modules/react-native/ReactAndroid",
59
- "REACT_ANDROID_BUILD_DIR=${appProject.rootDir}/../node_modules/react-native/ReactAndroid/build"
60
- cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
61
- cppFlags "-std=c++17"
62
- targets "reactnativekeyboardcontroller_modules"
63
- }
64
- }
65
- }
66
49
  ndk {
67
50
  abiFilters (*reactNativeArchitectures())
68
51
  }
69
52
  }
70
53
 
71
- if (isNewArchitectureEnabled()) {
72
- externalNativeBuild {
73
- ndkBuild {
74
- path "src/main/jni/Android.mk"
75
- }
76
- }
77
-
78
- packagingOptions {
79
- exclude "**/libreact_render_*.so"
80
- exclude "**/librrc_root.so"
81
- }
82
- }
83
-
84
54
  sourceSets {
85
55
  main {
86
56
  if (isNewArchitectureEnabled()) {
@@ -186,13 +156,3 @@ dependencies {
186
156
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
187
157
  implementation 'androidx.core:core-ktx:1.5.0-beta03'
188
158
  }
189
-
190
- if (isNewArchitectureEnabled()) {
191
- react {
192
- reactNativeDir = rootProject.file("../node_modules/react-native/")
193
- jsRootDir = file("../src/")
194
- codegenDir = rootProject.file("../node_modules/react-native-codegen/")
195
- libraryName = "reactnativekeyboardcontroller"
196
- codegenJavaPackageName = "com.reactnativekeyboardcontroller"
197
- }
198
- }
@@ -74,14 +74,16 @@ class KeyboardAnimationCallback(
74
74
  val keyboardHeight = getCurrentKeyboardHeight()
75
75
 
76
76
  this.emitEvent("KeyboardController::keyboardWillShow", getEventParams(keyboardHeight))
77
+ this.sendEventToJS(KeyboardTransitionEvent(view.id, "topKeyboardMoveStart", keyboardHeight, 1.0))
77
78
 
78
- val animation = ValueAnimator.ofInt(-this.persistentKeyboardHeight, -keyboardHeight)
79
+ val animation = ValueAnimator.ofInt(this.persistentKeyboardHeight, keyboardHeight)
79
80
  animation.addUpdateListener { animator ->
80
81
  val toValue = animator.animatedValue as Int
81
- this.sendEventToJS(KeyboardTransitionEvent(view.id, toValue, -toValue.toDouble() / keyboardHeight))
82
+ this.sendEventToJS(KeyboardTransitionEvent(view.id, "topKeyboardMove", toValue, toValue.toDouble() / keyboardHeight))
82
83
  }
83
84
  animation.doOnEnd {
84
85
  this.emitEvent("KeyboardController::keyboardDidShow", getEventParams(keyboardHeight))
86
+ this.sendEventToJS(KeyboardTransitionEvent(view.id, "topKeyboardMoveEnd", keyboardHeight, 1.0))
85
87
  }
86
88
  animation.setDuration(250).startDelay = 0
87
89
  animation.start()
@@ -108,6 +110,7 @@ class KeyboardAnimationCallback(
108
110
  this.emitEvent("KeyboardController::" + if (!isKeyboardVisible) "keyboardWillHide" else "keyboardWillShow", getEventParams(keyboardHeight))
109
111
 
110
112
  Log.i(TAG, "HEIGHT:: $keyboardHeight")
113
+ this.sendEventToJS(KeyboardTransitionEvent(view.id, "topKeyboardMoveStart", keyboardHeight, if (!isKeyboardVisible) 0.0 else 1.0))
111
114
 
112
115
  return super.onStart(animation, bounds)
113
116
  }
@@ -128,7 +131,7 @@ class KeyboardAnimationCallback(
128
131
  val diff = Insets.subtract(typesInset, otherInset).let {
129
132
  Insets.max(it, Insets.NONE)
130
133
  }
131
- val diffY = (diff.top - diff.bottom).toFloat()
134
+ val diffY = (diff.bottom - diff.top).toFloat()
132
135
  val height = toDp(diffY, context)
133
136
 
134
137
  var progress = 0.0
@@ -139,7 +142,7 @@ class KeyboardAnimationCallback(
139
142
  }
140
143
  Log.i(TAG, "DiffY: $diffY $height $progress")
141
144
 
142
- this.sendEventToJS(KeyboardTransitionEvent(view.id, height, progress))
145
+ this.sendEventToJS(KeyboardTransitionEvent(view.id, "topKeyboardMove", height, progress))
143
146
 
144
147
  return insets
145
148
  }
@@ -150,6 +153,7 @@ class KeyboardAnimationCallback(
150
153
  isTransitioning = false
151
154
  this.persistentKeyboardHeight = getCurrentKeyboardHeight()
152
155
  this.emitEvent("KeyboardController::" + if (!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow", getEventParams(this.persistentKeyboardHeight))
156
+ this.sendEventToJS(KeyboardTransitionEvent(view.id, "topKeyboardMoveEnd", this.persistentKeyboardHeight, if (!isKeyboardVisible) 0.0 else 1.0))
153
157
  }
154
158
 
155
159
  private fun isKeyboardVisible(): Boolean {
@@ -1,21 +1,57 @@
1
1
  package com.reactnativekeyboardcontroller
2
2
 
3
- import com.facebook.react.ReactPackage
3
+ import androidx.annotation.Nullable
4
+ import com.facebook.react.TurboReactPackage
4
5
  import com.facebook.react.bridge.NativeModule
5
6
  import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.module.model.ReactModuleInfo
8
+ import com.facebook.react.module.model.ReactModuleInfoProvider
6
9
  import com.facebook.react.uimanager.ViewManager
7
- import com.facebook.soloader.SoLoader
8
10
 
9
- class KeyboardControllerPackage : ReactPackage {
10
- override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11
- return listOf(KeyboardControllerModule(reactContext), StatusBarManagerCompatModule(reactContext))
11
+ class KeyboardControllerPackage : TurboReactPackage() {
12
+ @Nullable
13
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
14
+ return when (name) {
15
+ KeyboardControllerModuleImpl.NAME -> {
16
+ KeyboardControllerModule(reactContext)
17
+ }
18
+ StatusBarManagerCompatImpl.NAME -> {
19
+ StatusBarManagerCompatModule(reactContext)
20
+ }
21
+ else -> {
22
+ null
23
+ }
24
+ }
12
25
  }
13
26
 
14
- override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15
- if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
16
- SoLoader.loadLibrary("reactnativekeyboardcontroller_modules")
27
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
28
+ return ReactModuleInfoProvider {
29
+ val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
30
+ val isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
31
+
32
+ moduleInfos[KeyboardControllerModuleImpl.NAME] = ReactModuleInfo(
33
+ KeyboardControllerModuleImpl.NAME,
34
+ KeyboardControllerModuleImpl.NAME,
35
+ false, // canOverrideExistingModule
36
+ false, // needsEagerInit
37
+ true, // hasConstants
38
+ false, // isCxxModule
39
+ isTurboModule // isTurboModule
40
+ )
41
+ moduleInfos[StatusBarManagerCompatImpl.NAME] = ReactModuleInfo(
42
+ StatusBarManagerCompatImpl.NAME,
43
+ StatusBarManagerCompatImpl.NAME,
44
+ false, // canOverrideExistingModule
45
+ false, // needsEagerInit
46
+ true, // hasConstants
47
+ false, // isCxxModule
48
+ isTurboModule // isTurboModule
49
+ )
50
+ moduleInfos
17
51
  }
52
+ }
18
53
 
54
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
19
55
  return listOf(KeyboardControllerViewManager(reactContext))
20
56
  }
21
57
  }
@@ -9,7 +9,6 @@ import com.facebook.react.bridge.ReactApplicationContext
9
9
  import com.facebook.react.common.MapBuilder
10
10
  import com.facebook.react.uimanager.ThemedReactContext
11
11
  import com.facebook.react.views.view.ReactViewGroup
12
- import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent
13
12
 
14
13
  class KeyboardControllerViewManagerImpl(reactContext: ReactApplicationContext) {
15
14
  private val TAG = KeyboardControllerViewManagerImpl::class.qualifiedName
@@ -58,8 +57,12 @@ class KeyboardControllerViewManagerImpl(reactContext: ReactApplicationContext) {
58
57
 
59
58
  fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
60
59
  val map: MutableMap<String, Any> = MapBuilder.of(
61
- KeyboardTransitionEvent.EVENT_NAME,
62
- MapBuilder.of("registrationName", "onKeyboardMove")
60
+ "topKeyboardMove",
61
+ MapBuilder.of("registrationName", "onKeyboardMove"),
62
+ "topKeyboardMoveStart",
63
+ MapBuilder.of("registrationName", "onKeyboardMoveStart"),
64
+ "topKeyboardMoveEnd",
65
+ MapBuilder.of("registrationName", "onKeyboardMoveEnd"),
63
66
  )
64
67
 
65
68
  return map
@@ -4,8 +4,8 @@ import com.facebook.react.bridge.Arguments
4
4
  import com.facebook.react.uimanager.events.Event
5
5
  import com.facebook.react.uimanager.events.RCTEventEmitter
6
6
 
7
- class KeyboardTransitionEvent(private val viewId: Int, private val height: Int, private val progress: Double) : Event<KeyboardTransitionEvent>(viewId) {
8
- override fun getEventName() = EVENT_NAME
7
+ class KeyboardTransitionEvent(viewId: Int, private val event: String, private val height: Int, private val progress: Double) : Event<KeyboardTransitionEvent>(viewId) {
8
+ override fun getEventName() = event
9
9
 
10
10
  // TODO: All events for a given view can be coalesced?
11
11
  override fun getCoalescingKey(): Short = 0
@@ -16,8 +16,4 @@ class KeyboardTransitionEvent(private val viewId: Int, private val height: Int,
16
16
  map.putInt("height", height)
17
17
  rctEventEmitter.receiveEvent(viewTag, eventName, map)
18
18
  }
19
-
20
- companion object {
21
- const val EVENT_NAME = "topKeyboardMove"
22
- }
23
19
  }
@@ -1,5 +1,9 @@
1
1
  disabled_rules:
2
2
  - trailing_comma
3
3
 
4
+ line_length:
5
+ warning: 120
6
+ ignores_urls: true
7
+
4
8
  excluded:
5
9
  - Pods
@@ -187,7 +187,7 @@
187
187
  GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
188
188
  GCC_WARN_UNUSED_FUNCTION = YES;
189
189
  GCC_WARN_UNUSED_VARIABLE = YES;
190
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
190
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
191
191
  MTL_ENABLE_DEBUG_INFO = YES;
192
192
  ONLY_ACTIVE_ARCH = YES;
193
193
  SDKROOT = iphoneos;
@@ -230,7 +230,7 @@
230
230
  GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
231
231
  GCC_WARN_UNUSED_FUNCTION = YES;
232
232
  GCC_WARN_UNUSED_VARIABLE = YES;
233
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
233
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
234
234
  MTL_ENABLE_DEBUG_INFO = NO;
235
235
  SDKROOT = iphoneos;
236
236
  VALIDATE_PRODUCT = YES;
@@ -12,7 +12,7 @@
12
12
  // Thanks to this guard, we won't import this header when we build for the old architecture.
13
13
  #ifdef RCT_NEW_ARCH_ENABLED
14
14
  #import <FBReactNativeSpec/FBReactNativeSpec.h>
15
- #import "RNKeyboardControllerSpec.h"
15
+ #import <reactnativekeyboardcontroller/reactnativekeyboardcontroller.h>
16
16
  #endif
17
17
 
18
18
  #import "KeyboardControllerModule-Header.h"
@@ -12,10 +12,10 @@
12
12
  #import "KeyboardMoveEvent.h"
13
13
  #import "react_native_keyboard_controller-Swift.h"
14
14
 
15
- #import <react/renderer/components/RNKeyboardControllerViewSpec/ComponentDescriptors.h>
16
- #import <react/renderer/components/RNKeyboardControllerViewSpec/EventEmitters.h>
17
- #import <react/renderer/components/RNKeyboardControllerViewSpec/Props.h>
18
- #import <react/renderer/components/RNKeyboardControllerViewSpec/RCTComponentViewHelpers.h>
15
+ #import <react/renderer/components/reactnativekeyboardcontroller/ComponentDescriptors.h>
16
+ #import <react/renderer/components/reactnativekeyboardcontroller/EventEmitters.h>
17
+ #import <react/renderer/components/reactnativekeyboardcontroller/Props.h>
18
+ #import <react/renderer/components/reactnativekeyboardcontroller/RCTComponentViewHelpers.h>
19
19
 
20
20
  #import <React/RCTBridge+Private.h>
21
21
 
@@ -44,13 +44,30 @@ using namespace facebook::react;
44
44
  _props = defaultProps;
45
45
 
46
46
  observer = [[KeyboardMovementObserver alloc]
47
- initWithHandler:^(NSNumber *height, NSNumber *progress) {
47
+ initWithHandler:^(NSString *event, NSNumber *height, NSNumber *progress) {
48
48
  if (self->_eventEmitter) {
49
- std::dynamic_pointer_cast<const facebook::react::KeyboardControllerViewEventEmitter>(
50
- self->_eventEmitter)
51
- ->onKeyboardMove(
52
- facebook::react::KeyboardControllerViewEventEmitter::OnKeyboardMove{
53
- .height = [height intValue], .progress = static_cast<Float>(self.tag)});
49
+ // TODO: use reflection to reduce code duplication?
50
+ if ([event isEqualToString:@"onKeyboardMoveStart"]) {
51
+ std::dynamic_pointer_cast<const facebook::react::KeyboardControllerViewEventEmitter>(
52
+ self->_eventEmitter)
53
+ ->onKeyboardMoveStart(
54
+ facebook::react::KeyboardControllerViewEventEmitter::OnKeyboardMoveStart{
55
+ .height = [height intValue], .progress = [progress floatValue]});
56
+ }
57
+ if ([event isEqualToString:@"onKeyboardMove"]) {
58
+ std::dynamic_pointer_cast<const facebook::react::KeyboardControllerViewEventEmitter>(
59
+ self->_eventEmitter)
60
+ ->onKeyboardMove(
61
+ facebook::react::KeyboardControllerViewEventEmitter::OnKeyboardMove{
62
+ .height = [height intValue], .progress = [progress floatValue]});
63
+ }
64
+ if ([event isEqualToString:@"onKeyboardMoveEnd"]) {
65
+ std::dynamic_pointer_cast<const facebook::react::KeyboardControllerViewEventEmitter>(
66
+ self->_eventEmitter)
67
+ ->onKeyboardMoveEnd(
68
+ facebook::react::KeyboardControllerViewEventEmitter::OnKeyboardMoveEnd{
69
+ .height = [height intValue], .progress = [progress floatValue]});
70
+ }
54
71
  }
55
72
 
56
73
  // TODO: use built-in _eventEmitter once NativeAnimated module will use ModernEventemitter
@@ -58,6 +75,7 @@ using namespace facebook::react;
58
75
  if (bridge) {
59
76
  KeyboardMoveEvent *keyboardMoveEvent =
60
77
  [[KeyboardMoveEvent alloc] initWithReactTag:@(self.tag)
78
+ event:event
61
79
  height:height
62
80
  progress:progress];
63
81
  [bridge.eventDispatcher sendEvent:keyboardMoveEvent];
@@ -2,6 +2,8 @@
2
2
 
3
3
  @interface RCT_EXTERN_MODULE (KeyboardControllerViewManager, RCTViewManager)
4
4
 
5
+ RCT_EXPORT_VIEW_PROPERTY(onKeyboardMoveStart, RCTDirectEventBlock);
5
6
  RCT_EXPORT_VIEW_PROPERTY(onKeyboardMove, RCTDirectEventBlock);
7
+ RCT_EXPORT_VIEW_PROPERTY(onKeyboardMoveEnd, RCTDirectEventBlock);
6
8
 
7
9
  @end
@@ -12,7 +12,9 @@ class KeyboardControllerViewManager: RCTViewManager {
12
12
  class KeyboardControllerView: UIView {
13
13
  private var keyboardObserver: KeyboardMovementObserver?
14
14
  private var eventDispatcher: RCTEventDispatcherProtocol
15
+ @objc var onKeyboardMoveStart: RCTDirectEventBlock?
15
16
  @objc var onKeyboardMove: RCTDirectEventBlock?
17
+ @objc var onKeyboardMoveEnd: RCTDirectEventBlock?
16
18
 
17
19
  init(frame: CGRect, eventDispatcher: RCTEventDispatcherProtocol) {
18
20
  self.eventDispatcher = eventDispatcher
@@ -39,10 +41,11 @@ class KeyboardControllerView: UIView {
39
41
  }
40
42
  }
41
43
 
42
- func onEvent(height: NSNumber, progress: NSNumber) {
44
+ func onEvent(event: NSString, height: NSNumber, progress: NSNumber) {
43
45
  eventDispatcher.send(
44
46
  KeyboardMoveEvent(
45
47
  reactTag: reactTag,
48
+ event: event as String,
46
49
  height: height,
47
50
  progress: progress
48
51
  )
@@ -12,6 +12,7 @@
12
12
  @interface KeyboardMoveEvent : NSObject <RCTEvent>
13
13
 
14
14
  - (instancetype)initWithReactTag:(NSNumber *)reactTag
15
+ event:(NSString *)event
15
16
  height:(NSNumber *)height
16
17
  progress:(NSNumber *)progress;
17
18
 
@@ -19,13 +19,14 @@
19
19
  @synthesize eventName = _eventName;
20
20
 
21
21
  - (instancetype)initWithReactTag:(NSNumber *)reactTag
22
+ event:(NSString *)event
22
23
  height:(NSNumber *)height
23
24
  progress:(NSNumber *)progress
24
25
  {
25
26
  RCTAssertParam(reactTag);
26
27
 
27
28
  if ((self = [super init])) {
28
- _eventName = @"onKeyboardMove";
29
+ _eventName = [event copy];
29
30
  _viewTag = reactTag;
30
31
  _progress = progress;
31
32
  _height = height;
@@ -10,10 +10,31 @@ import Foundation
10
10
 
11
11
  @objc(KeyboardMovementObserver)
12
12
  public class KeyboardMovementObserver: NSObject {
13
- var onEvent: (NSNumber, NSNumber) -> Void
13
+ // class members
14
+ var onEvent: (NSString, NSNumber, NSNumber) -> Void
14
15
  var onNotify: (String, Any) -> Void
16
+ // progress tracker
17
+ private var _keyboardView: UIView?
18
+ private var keyboardView: UIView? {
19
+ let windowsCount = UIApplication.shared.windows.count
15
20
 
16
- @objc public init(handler: @escaping (NSNumber, NSNumber) -> Void, onNotify: @escaping (String, Any) -> Void) {
21
+ if _keyboardView == nil || windowsCount != _windowsCount {
22
+ _keyboardView = findKeyboardView()
23
+ _windowsCount = windowsCount
24
+ }
25
+
26
+ return _keyboardView
27
+ }
28
+
29
+ private var _windowsCount: Int = 0
30
+ private var prevKeyboardPosition = 0.0
31
+ private var displayLink: CADisplayLink?
32
+ private var keyboardHeight: CGFloat = 0.0
33
+
34
+ @objc public init(
35
+ handler: @escaping (NSString, NSNumber, NSNumber) -> Void,
36
+ onNotify: @escaping (String, Any) -> Void
37
+ ) {
17
38
  onEvent = handler
18
39
  self.onNotify = onNotify
19
40
  }
@@ -53,12 +74,15 @@ public class KeyboardMovementObserver: NSObject {
53
74
  @objc func keyboardWillAppear(_ notification: Notification) {
54
75
  if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
55
76
  let keyboardHeight = keyboardFrame.cgRectValue.size.height
77
+ self.keyboardHeight = keyboardHeight
56
78
 
57
79
  var data = [AnyHashable: Any]()
58
80
  data["height"] = keyboardHeight
59
81
 
60
- onEvent(Float(-keyboardHeight) as NSNumber, 1)
82
+ onEvent("onKeyboardMoveStart", Float(keyboardHeight) as NSNumber, 1)
61
83
  onNotify("KeyboardController::keyboardWillShow", data)
84
+
85
+ setupKeyboardWatcher()
62
86
  }
63
87
  }
64
88
 
@@ -66,18 +90,24 @@ public class KeyboardMovementObserver: NSObject {
66
90
  var data = [AnyHashable: Any]()
67
91
  data["height"] = 0
68
92
 
69
- onEvent(0, 0)
93
+ onEvent("onKeyboardMoveStart", 0, 0)
70
94
  onNotify("KeyboardController::keyboardWillHide", data)
95
+
96
+ setupKeyboardWatcher()
71
97
  }
72
98
 
73
99
  @objc func keyboardDidAppear(_ notification: Notification) {
74
100
  if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
75
101
  let keyboardHeight = keyboardFrame.cgRectValue.size.height
102
+ self.keyboardHeight = keyboardHeight
76
103
 
77
104
  var data = [AnyHashable: Any]()
78
105
  data["height"] = keyboardHeight
79
106
 
107
+ onEvent("onKeyboardMoveEnd", keyboardHeight as NSNumber, 1)
80
108
  onNotify("KeyboardController::keyboardDidShow", data)
109
+
110
+ removeKeyboardWatcher()
81
111
  }
82
112
  }
83
113
 
@@ -85,6 +115,61 @@ public class KeyboardMovementObserver: NSObject {
85
115
  var data = [AnyHashable: Any]()
86
116
  data["height"] = 0
87
117
 
118
+ onEvent("onKeyboardMoveEnd", 0 as NSNumber, 0)
88
119
  onNotify("KeyboardController::keyboardDidHide", data)
120
+
121
+ removeKeyboardWatcher()
122
+ }
123
+
124
+ @objc func setupKeyboardWatcher() {
125
+ displayLink = CADisplayLink(target: self, selector: #selector(updateKeyboardFrame))
126
+ displayLink?.preferredFramesPerSecond = 120 // will fallback to 60 fps for devices without Pro Motion display
127
+ displayLink?.add(to: .main, forMode: .common)
128
+ }
129
+
130
+ @objc func removeKeyboardWatcher() {
131
+ displayLink?.invalidate()
132
+ displayLink = nil
133
+ }
134
+
135
+ // https://stackoverflow.com/questions/32598490/show-uiview-with-buttons-over-keyboard-like-in-skype-viber-messengers-swift-i
136
+ func findKeyboardView() -> UIView? {
137
+ var result: UIView?
138
+
139
+ let windows = UIApplication.shared.windows
140
+ for window in windows {
141
+ if window.description.hasPrefix("<UITextEffectsWindow") {
142
+ for subview in window.subviews {
143
+ if subview.description.hasPrefix("<UIInputSetContainerView") {
144
+ for hostView in subview.subviews {
145
+ if hostView.description.hasPrefix("<UIInputSetHostView") {
146
+ result = hostView as? UIView
147
+ break
148
+ }
149
+ }
150
+ break
151
+ }
152
+ }
153
+ break
154
+ }
155
+ }
156
+ return result
157
+ }
158
+
159
+ @objc func updateKeyboardFrame() {
160
+ if keyboardView == nil {
161
+ return
162
+ }
163
+
164
+ var keyboardFrameY = keyboardView!.layer.presentation()!.frame.origin.y
165
+ var keyboardWindowH = keyboardView!.window!.bounds.size.height
166
+ var keyboardPosition = keyboardWindowH - keyboardFrameY
167
+
168
+ if keyboardPosition == prevKeyboardPosition || keyboardFrameY == 0 {
169
+ return
170
+ }
171
+
172
+ prevKeyboardPosition = keyboardPosition
173
+ onEvent("onKeyboardMove", keyboardPosition as NSNumber, keyboardPosition / CGFloat(keyboardHeight) as NSNumber)
89
174
  }
90
175
  }
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.useReanimatedKeyboardAnimation = exports.useKeyboardAnimation = exports.styles = exports.KeyboardProvider = exports.KeyboardContext = void 0;
6
+ exports.styles = exports.KeyboardProvider = void 0;
7
7
 
8
8
  var _react = _interopRequireWildcard(require("react"));
9
9
 
@@ -11,6 +11,10 @@ var _reactNative = require("react-native");
11
11
 
12
12
  var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
13
13
 
14
+ var _context = require("./context");
15
+
16
+ var _internal = require("./internal");
17
+
14
18
  var _native = require("./native");
15
19
 
16
20
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
@@ -19,59 +23,6 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
19
23
 
20
24
  const KeyboardControllerViewAnimated = _reactNativeReanimated.default.createAnimatedComponent(_reactNative.Animated.createAnimatedComponent(_native.KeyboardControllerView));
21
25
 
22
- const defaultContext = {
23
- animated: {
24
- progress: new _reactNative.Animated.Value(0),
25
- height: new _reactNative.Animated.Value(0)
26
- },
27
- reanimated: {
28
- progress: {
29
- value: 0
30
- },
31
- height: {
32
- value: 0
33
- }
34
- }
35
- };
36
-
37
- const KeyboardContext = /*#__PURE__*/_react.default.createContext(defaultContext);
38
-
39
- exports.KeyboardContext = KeyboardContext;
40
-
41
- const useKeyboardAnimation = () => {
42
- (0, _native.useResizeMode)();
43
- const context = (0, _react.useContext)(KeyboardContext);
44
- return context.animated;
45
- };
46
-
47
- exports.useKeyboardAnimation = useKeyboardAnimation;
48
-
49
- const useReanimatedKeyboardAnimation = () => {
50
- (0, _native.useResizeMode)();
51
- const context = (0, _react.useContext)(KeyboardContext);
52
- return context.reanimated;
53
- };
54
-
55
- exports.useReanimatedKeyboardAnimation = useReanimatedKeyboardAnimation;
56
-
57
- function useAnimatedKeyboardHandler(handlers, dependencies) {
58
- const {
59
- context,
60
- doDependenciesDiffer
61
- } = (0, _reactNativeReanimated.useHandler)(handlers, dependencies);
62
- return (0, _reactNativeReanimated.useEvent)(event => {
63
- 'worklet';
64
-
65
- const {
66
- onKeyboardMove
67
- } = handlers;
68
-
69
- if (onKeyboardMove && event.eventName.endsWith('onKeyboardMove')) {
70
- onKeyboardMove(event, context);
71
- }
72
- }, ['onKeyboardMove'], doDependenciesDiffer);
73
- }
74
-
75
26
  const styles = _reactNative.StyleSheet.create({
76
27
  container: {
77
28
  flex: 1
@@ -89,19 +40,27 @@ const KeyboardProvider = _ref => {
89
40
  children,
90
41
  statusBarTranslucent
91
42
  } = _ref;
43
+ // animated values
92
44
  const progress = (0, _react.useRef)(new _reactNative.Animated.Value(0)).current;
93
- const height = (0, _react.useRef)(new _reactNative.Animated.Value(0)).current;
45
+ const height = (0, _react.useRef)(new _reactNative.Animated.Value(0)).current; // shared values
46
+
94
47
  const progressSV = (0, _reactNativeReanimated.useSharedValue)(0);
95
48
  const heightSV = (0, _reactNativeReanimated.useSharedValue)(0);
49
+ const {
50
+ setHandlers,
51
+ broadcast
52
+ } = (0, _internal.useSharedHandlers)(); // memo
53
+
96
54
  const context = (0, _react.useMemo)(() => ({
97
55
  animated: {
98
56
  progress: progress,
99
- height: height
57
+ height: _reactNative.Animated.multiply(height, -1)
100
58
  },
101
59
  reanimated: {
102
60
  progress: progressSV,
103
61
  height: heightSV
104
- }
62
+ },
63
+ setHandlers
105
64
  }), []);
106
65
  const style = (0, _react.useMemo)(() => [styles.hidden, {
107
66
  transform: [{
@@ -117,20 +76,42 @@ const KeyboardProvider = _ref => {
117
76
  }
118
77
  }], {
119
78
  useNativeDriver: true
120
- }), []);
121
- const handler = useAnimatedKeyboardHandler({
79
+ }), []); // handlers
80
+
81
+ const updateSharedValues = (event, platforms) => {
82
+ 'worklet';
83
+
84
+ if (platforms.includes(_reactNative.Platform.OS)) {
85
+ progressSV.value = event.progress;
86
+ heightSV.value = -event.height;
87
+ }
88
+ };
89
+
90
+ const handler = (0, _internal.useAnimatedKeyboardHandler)({
91
+ onKeyboardMoveStart: event => {
92
+ 'worklet';
93
+
94
+ broadcast('onStart', event);
95
+ updateSharedValues(event, ['ios']);
96
+ },
122
97
  onKeyboardMove: event => {
123
98
  'worklet';
124
99
 
125
- progressSV.value = event.progress;
126
- heightSV.value = event.height;
100
+ broadcast('onMove', event);
101
+ updateSharedValues(event, ['android']);
102
+ },
103
+ onKeyboardMoveEnd: event => {
104
+ 'worklet';
105
+
106
+ broadcast('onEnd', event);
127
107
  }
128
108
  }, []);
129
- return /*#__PURE__*/_react.default.createElement(KeyboardContext.Provider, {
109
+ return /*#__PURE__*/_react.default.createElement(_context.KeyboardContext.Provider, {
130
110
  value: context
131
111
  }, /*#__PURE__*/_react.default.createElement(KeyboardControllerViewAnimated, {
132
112
  onKeyboardMoveReanimated: handler,
133
- onKeyboardMove: onKeyboardMove,
113
+ onKeyboardMoveStart: _reactNative.Platform.OS === 'ios' ? onKeyboardMove : undefined,
114
+ onKeyboardMove: _reactNative.Platform.OS === 'android' ? onKeyboardMove : undefined,
134
115
  statusBarTranslucent: statusBarTranslucent,
135
116
  style: styles.container
136
117
  }, /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, {