react-native-keyboard-controller 1.14.0 → 1.14.1

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.
@@ -0,0 +1,7 @@
1
+ package com.reactnativekeyboardcontroller.constants
2
+
3
+ import android.os.Build
4
+
5
+ object Keyboard {
6
+ val IS_ANIMATION_EMULATED = Build.VERSION.SDK_INT < Build.VERSION_CODES.R
7
+ }
@@ -1,6 +1,5 @@
1
1
  package com.reactnativekeyboardcontroller.listeners
2
2
 
3
- import android.os.Build
4
3
  import android.view.View
5
4
  import android.view.ViewTreeObserver.OnGlobalFocusChangeListener
6
5
  import androidx.core.graphics.Insets
@@ -14,6 +13,7 @@ import com.facebook.react.uimanager.ThemedReactContext
14
13
  import com.facebook.react.uimanager.UIManagerHelper
15
14
  import com.facebook.react.views.textinput.ReactEditText
16
15
  import com.facebook.react.views.view.ReactViewGroup
16
+ import com.reactnativekeyboardcontroller.constants.Keyboard
17
17
  import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent
18
18
  import com.reactnativekeyboardcontroller.extensions.dispatchEvent
19
19
  import com.reactnativekeyboardcontroller.extensions.dp
@@ -24,7 +24,7 @@ import com.reactnativekeyboardcontroller.log.Logger
24
24
  import kotlin.math.abs
25
25
 
26
26
  private val TAG = KeyboardAnimationCallback::class.qualifiedName
27
- private val isResizeHandledInCallbackMethods = Build.VERSION.SDK_INT < Build.VERSION_CODES.R
27
+ private val isResizeHandledInCallbackMethods = Keyboard.IS_ANIMATION_EMULATED
28
28
 
29
29
  data class KeyboardAnimationCallbackConfig(
30
30
  val persistentInsetTypes: Int,
@@ -33,13 +33,22 @@ data class KeyboardAnimationCallbackConfig(
33
33
  val hasTranslucentNavigationBar: Boolean = false,
34
34
  )
35
35
 
36
+ interface Suspendable {
37
+ var isSuspended: Boolean
38
+
39
+ fun suspend(suspended: Boolean) {
40
+ isSuspended = suspended
41
+ }
42
+ }
43
+
36
44
  class KeyboardAnimationCallback(
37
45
  val eventPropagationView: ReactViewGroup,
38
46
  val view: View,
39
47
  val context: ThemedReactContext?,
40
48
  private val config: KeyboardAnimationCallbackConfig,
41
49
  ) : WindowInsetsAnimationCompat.Callback(config.dispatchMode),
42
- OnApplyWindowInsetsListener {
50
+ OnApplyWindowInsetsListener,
51
+ Suspendable {
43
52
  private val surfaceId = UIManagerHelper.getSurfaceId(eventPropagationView)
44
53
 
45
54
  // state variables
@@ -50,6 +59,7 @@ class KeyboardAnimationCallback(
50
59
  private var duration = 0
51
60
  private var viewTagFocused = -1
52
61
  private var animationsToSkip = hashSetOf<WindowInsetsAnimationCompat>()
62
+ override var isSuspended: Boolean = false
53
63
 
54
64
  // listeners
55
65
  private val focusListener =
@@ -147,7 +157,7 @@ class KeyboardAnimationCallback(
147
157
  this.onKeyboardResized(keyboardHeight)
148
158
  }
149
159
 
150
- return WindowInsetsCompat.CONSUMED
160
+ return insets
151
161
  }
152
162
 
153
163
  @Suppress("detekt:ReturnCount")
@@ -155,7 +165,7 @@ class KeyboardAnimationCallback(
155
165
  animation: WindowInsetsAnimationCompat,
156
166
  bounds: WindowInsetsAnimationCompat.BoundsCompat,
157
167
  ): WindowInsetsAnimationCompat.BoundsCompat {
158
- if (!animation.isKeyboardAnimation) {
168
+ if (!animation.isKeyboardAnimation || isSuspended) {
159
169
  return bounds
160
170
  }
161
171
 
@@ -211,7 +221,13 @@ class KeyboardAnimationCallback(
211
221
  // onProgress() is called when any of the running animations progress...
212
222
 
213
223
  // ignore non-keyboard animation or animation that we intentionally want to skip
214
- runningAnimations.find { it.isKeyboardAnimation && !animationsToSkip.contains(it) } ?: return insets
224
+ val shouldSkipAnimation =
225
+ runningAnimations.find {
226
+ it.isKeyboardAnimation && !animationsToSkip.contains(it)
227
+ } == null
228
+ if (isSuspended || shouldSkipAnimation) {
229
+ return insets
230
+ }
215
231
 
216
232
  // First we get the insets which are potentially deferred
217
233
  val typesInset = insets.getInsets(config.deferredInsetTypes)
@@ -262,7 +278,7 @@ class KeyboardAnimationCallback(
262
278
  override fun onEnd(animation: WindowInsetsAnimationCompat) {
263
279
  super.onEnd(animation)
264
280
 
265
- if (!animation.isKeyboardAnimation) {
281
+ if (!animation.isKeyboardAnimation || isSuspended) {
266
282
  return
267
283
  }
268
284
 
@@ -311,10 +327,13 @@ class KeyboardAnimationCallback(
311
327
  duration = 0
312
328
  }
313
329
 
314
- fun syncKeyboardPosition() {
315
- val keyboardHeight = getCurrentKeyboardHeight()
330
+ fun syncKeyboardPosition(
331
+ height: Double? = null,
332
+ isVisible: Boolean? = null,
333
+ ) {
334
+ val keyboardHeight = height ?: getCurrentKeyboardHeight()
316
335
  // update internal state
317
- isKeyboardVisible = isKeyboardVisible()
336
+ isKeyboardVisible = isVisible ?: isKeyboardVisible()
318
337
  prevKeyboardHeight = keyboardHeight
319
338
  isTransitioning = false
320
339
  duration = 0
@@ -1,5 +1,6 @@
1
1
  package com.reactnativekeyboardcontroller.modal
2
2
 
3
+ import android.view.ViewGroup
3
4
  import android.view.WindowManager
4
5
  import androidx.core.view.ViewCompat
5
6
  import com.facebook.react.uimanager.ThemedReactContext
@@ -10,16 +11,20 @@ import com.facebook.react.uimanager.events.EventDispatcherListener
10
11
  import com.facebook.react.views.modal.ReactModalHostView
11
12
  import com.facebook.react.views.view.ReactViewGroup
12
13
  import com.reactnativekeyboardcontroller.BuildConfig
14
+ import com.reactnativekeyboardcontroller.constants.Keyboard
15
+ import com.reactnativekeyboardcontroller.extensions.removeSelf
13
16
  import com.reactnativekeyboardcontroller.listeners.KeyboardAnimationCallback
14
17
  import com.reactnativekeyboardcontroller.listeners.KeyboardAnimationCallbackConfig
15
18
  import com.reactnativekeyboardcontroller.log.Logger
16
19
 
17
20
  private val TAG = ModalAttachedWatcher::class.qualifiedName
21
+ private val areEventsComingFromOwnWindow = !Keyboard.IS_ANIMATION_EMULATED
18
22
 
19
23
  class ModalAttachedWatcher(
20
24
  private val view: ReactViewGroup,
21
25
  private val reactContext: ThemedReactContext,
22
26
  private val config: () -> KeyboardAnimationCallbackConfig,
27
+ private var callback: () -> KeyboardAnimationCallback?,
23
28
  ) : EventDispatcherListener {
24
29
  private val archType = if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) UIManagerType.FABRIC else UIManagerType.DEFAULT
25
30
  private val uiManager = UIManagerHelper.getUIManager(reactContext.reactApplicationContext, archType)
@@ -44,9 +49,13 @@ class ModalAttachedWatcher(
44
49
 
45
50
  val dialog = modal.dialog
46
51
  val window = dialog?.window
47
- val rootView = window?.decorView?.rootView
52
+ val rootView = window?.decorView?.rootView as ViewGroup?
48
53
 
49
54
  if (rootView != null) {
55
+ val eventView =
56
+ ReactViewGroup(reactContext).apply {
57
+ layoutParams = ViewGroup.LayoutParams(0, 0)
58
+ }
50
59
  val callback =
51
60
  KeyboardAnimationCallback(
52
61
  view = rootView,
@@ -55,16 +64,35 @@ class ModalAttachedWatcher(
55
64
  config = config(),
56
65
  )
57
66
 
67
+ rootView.addView(eventView)
68
+ // on Android < 12 all events for `WindowInsetsAnimationCallback`
69
+ // go through main `rootView`, so we don't need to stop main
70
+ // callback - otherwise keyboard transitions will not be animated
71
+ this.callback()?.suspend(areEventsComingFromOwnWindow)
58
72
  ViewCompat.setWindowInsetsAnimationCallback(rootView, callback)
59
- ViewCompat.setOnApplyWindowInsetsListener(rootView, callback)
73
+ ViewCompat.setOnApplyWindowInsetsListener(eventView, callback)
60
74
 
61
- dialog.setOnDismissListener {
75
+ if (areEventsComingFromOwnWindow) {
76
+ // when modal is shown then keyboard will be hidden by default
77
+ //
78
+ // - if events are coming from main window - then keyboard position
79
+ // will be synchronized from main window callback
80
+ // - if events are coming from modal window - then we need to update
81
+ // position ourself, because callback can be attached after keyboard
82
+ // auto-dismissal and we may miss some events and keyboard position
83
+ // will be outdated
84
+ callback.syncKeyboardPosition(0.0, false)
85
+ }
86
+
87
+ dialog?.setOnDismissListener {
62
88
  callback.syncKeyboardPosition()
63
89
  callback.destroy()
90
+ eventView.removeSelf()
91
+ this.callback()?.suspend(false)
64
92
  }
65
93
 
66
94
  // imitating edge-to-edge mode behavior
67
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
95
+ window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
68
96
  }
69
97
  }
70
98
 
@@ -2,6 +2,7 @@ package com.reactnativekeyboardcontroller.modules
2
2
 
3
3
  import android.animation.ArgbEvaluator
4
4
  import android.animation.ValueAnimator
5
+ import android.app.Activity
5
6
  import android.os.Build
6
7
  import androidx.annotation.RequiresApi
7
8
  import androidx.core.view.WindowInsetsCompat
@@ -11,6 +12,7 @@ import com.facebook.react.bridge.UiThreadUtil
11
12
  import com.reactnativekeyboardcontroller.extensions.rootView
12
13
  import com.reactnativekeyboardcontroller.log.Logger
13
14
  import com.reactnativekeyboardcontroller.views.EdgeToEdgeReactViewGroup
15
+ import java.lang.ref.WeakReference
14
16
 
15
17
  private val TAG = StatusBarManagerCompatModuleImpl::class.qualifiedName
16
18
 
@@ -18,6 +20,7 @@ class StatusBarManagerCompatModuleImpl(
18
20
  private val mReactContext: ReactApplicationContext,
19
21
  ) {
20
22
  private var controller: WindowInsetsControllerCompat? = null
23
+ private var lastActivity = WeakReference<Activity?>(null)
21
24
 
22
25
  fun setHidden(hidden: Boolean) {
23
26
  UiThreadUtil.runOnUiThread {
@@ -71,8 +74,9 @@ class StatusBarManagerCompatModuleImpl(
71
74
  }
72
75
 
73
76
  private fun getController(): WindowInsetsControllerCompat? {
74
- if (this.controller == null) {
75
- val activity = mReactContext.currentActivity
77
+ val activity = mReactContext.currentActivity
78
+
79
+ if (this.controller == null || activity != lastActivity.get()) {
76
80
  if (activity == null) {
77
81
  Logger.w(
78
82
  TAG,
@@ -82,6 +86,7 @@ class StatusBarManagerCompatModuleImpl(
82
86
  }
83
87
 
84
88
  val window = activity.window
89
+ lastActivity = WeakReference(activity)
85
90
 
86
91
  this.controller = WindowInsetsControllerCompat(window, window.decorView)
87
92
  }
@@ -47,7 +47,7 @@ class EdgeToEdgeReactViewGroup(
47
47
  )
48
48
 
49
49
  // managers/watchers
50
- private val modalAttachedWatcher = ModalAttachedWatcher(this, reactContext, ::config)
50
+ private val modalAttachedWatcher = ModalAttachedWatcher(this, reactContext, ::config, ::getKeyboardCallback)
51
51
 
52
52
  init {
53
53
  reactContext.setupWindowDimensionsListener()
@@ -195,6 +195,10 @@ class EdgeToEdgeReactViewGroup(
195
195
  }
196
196
  // endregion
197
197
 
198
+ // region Helpers
199
+ private fun getKeyboardCallback(): KeyboardAnimationCallback? = this.callback
200
+ // endregion
201
+
198
202
  // region Props setters
199
203
  fun setStatusBarTranslucent(isStatusBarTranslucent: Boolean) {
200
204
  this.isStatusBarTranslucent = isStatusBarTranslucent
@@ -6,6 +6,7 @@
6
6
  //
7
7
 
8
8
  import Foundation
9
+ import QuartzCore
9
10
 
10
11
  protocol KeyboardAnimationProtocol {
11
12
  var startTime: CFTimeInterval { get }
@@ -10,7 +10,7 @@ import Foundation
10
10
  import QuartzCore
11
11
 
12
12
  // swiftlint:disable identifier_name
13
- public class SpringAnimation: KeyboardAnimation {
13
+ public final class SpringAnimation: KeyboardAnimation {
14
14
  // internal variables
15
15
  private let zeta: Double // Damping ratio
16
16
  private let omega0: Double // Undamped angular frequency of the oscillator
@@ -15,13 +15,13 @@ import QuartzCore
15
15
  * This class calculates the progress of animations based on Bézier curve control points.
16
16
  * For more details on the Bézier curves, see [Desmos Graph](https://www.desmos.com/calculator/eynenh1aga?lang=en).
17
17
  */
18
- public class TimingAnimation: KeyboardAnimation {
18
+ public final class TimingAnimation: KeyboardAnimation {
19
19
  private let p1: CGPoint
20
20
  private let p2: CGPoint
21
21
 
22
22
  init(animation: CABasicAnimation, fromValue: Double, toValue: Double) {
23
23
  let timingFunction = animation.timingFunction
24
- var controlPoints: [Float] = [0, 0, 0, 0]
24
+ var controlPoints: ContiguousArray<Float> = ContiguousArray([0, 0, 0, 0])
25
25
  timingFunction?.getControlPoint(at: 1, values: &controlPoints[0])
26
26
  timingFunction?.getControlPoint(at: 2, values: &controlPoints[2])
27
27
  let p1 = CGPoint(x: CGFloat(controlPoints[0]), y: CGFloat(controlPoints[1]))
@@ -33,7 +33,20 @@ public class TimingAnimation: KeyboardAnimation {
33
33
  super.init(fromValue: fromValue, toValue: toValue, animation: animation)
34
34
  }
35
35
 
36
- func bezier(t: CGFloat, valueForPoint: (CGPoint) -> CGFloat) -> CGFloat {
36
+ // public functions
37
+ override func valueAt(time: Double) -> Double {
38
+ let x = time * Double(speed)
39
+ let frames = (animation?.duration ?? 0.0) * Double(speed)
40
+ let fraction = min(x / frames, 1)
41
+ let t = findTForX(xTarget: fraction)
42
+
43
+ let progress = bezierY(t: t)
44
+
45
+ return fromValue + (toValue - fromValue) * CGFloat(progress)
46
+ }
47
+
48
+ // private functions
49
+ private func bezier(t: CGFloat, valueForPoint: (CGPoint) -> CGFloat) -> CGFloat {
37
50
  let u = 1 - t
38
51
  let tt = t * t
39
52
  let uu = u * u
@@ -49,27 +62,15 @@ public class TimingAnimation: KeyboardAnimation {
49
62
  return term1 + term2 + term3
50
63
  }
51
64
 
52
- func bezierY(t: CGFloat) -> CGFloat {
65
+ private func bezierY(t: CGFloat) -> CGFloat {
53
66
  return bezier(t: t) { $0.y }
54
67
  }
55
68
 
56
- func bezierX(t: CGFloat) -> CGFloat {
69
+ private func bezierX(t: CGFloat) -> CGFloat {
57
70
  return bezier(t: t) { $0.x }
58
71
  }
59
72
 
60
- // public functions
61
- override func valueAt(time: Double) -> Double {
62
- let x = time * Double(speed)
63
- let frames = (animation?.duration ?? 0.0) * Double(speed)
64
- let fraction = min(x / frames, 1)
65
- let t = findTForX(xTarget: fraction)
66
-
67
- let progress = bezierY(t: t)
68
-
69
- return fromValue + (toValue - fromValue) * CGFloat(progress)
70
- }
71
-
72
- func findTForX(xTarget: CGFloat, epsilon: CGFloat = 0.0001, maxIterations: Int = 100) -> CGFloat {
73
+ private func findTForX(xTarget: CGFloat, epsilon: CGFloat = 0.0001, maxIterations: Int = 100) -> CGFloat {
73
74
  var t: CGFloat = 0.5 // Start with an initial guess of t = 0.5
74
75
  for _ in 0 ..< maxIterations {
75
76
  let currentX = bezierX(t: t) // Compute the x-coordinate at t
@@ -84,7 +85,7 @@ public class TimingAnimation: KeyboardAnimation {
84
85
  return t // Return the approximation of t
85
86
  }
86
87
 
87
- func bezierDerivative(t: CGFloat, valueForPoint: (CGPoint) -> CGFloat) -> CGFloat {
88
+ private func bezierDerivative(t: CGFloat, valueForPoint: (CGPoint) -> CGFloat) -> CGFloat {
88
89
  let u = 1 - t
89
90
  let uu = u * u
90
91
  let tt = t * t
@@ -100,7 +101,7 @@ public class TimingAnimation: KeyboardAnimation {
100
101
  return term1 + term2 + term3
101
102
  }
102
103
 
103
- func bezierXDerivative(t: CGFloat) -> CGFloat {
104
+ private func bezierXDerivative(t: CGFloat) -> CGFloat {
104
105
  return bezierDerivative(t: t) { $0.x }
105
106
  }
106
107
  }
@@ -9,6 +9,22 @@ import Foundation
9
9
  import UIKit
10
10
 
11
11
  public extension UIApplication {
12
+ var activeWindow: UIWindow? {
13
+ if #available(iOS 13.0, *) {
14
+ for scene in connectedScenes {
15
+ if scene.activationState == .foregroundActive,
16
+ let windowScene = scene as? UIWindowScene,
17
+ let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow })
18
+ {
19
+ return keyWindow
20
+ }
21
+ }
22
+ return nil
23
+ } else {
24
+ return windows.last { $0.isKeyWindow }
25
+ }
26
+ }
27
+
12
28
  static func topViewController(
13
29
  base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
14
30
  ) -> UIViewController? {
@@ -38,7 +38,7 @@ public extension UIWindow {
38
38
 
39
39
  func getTopWindow() -> UIWindow? {
40
40
  // Return the keyboard window if it's available, otherwise return the last window
41
- return keyboardWindow ?? UIApplication.shared.windows.last
41
+ return keyboardWindow ?? UIApplication.shared.activeWindow
42
42
  }
43
43
  }
44
44
 
@@ -31,6 +31,12 @@ const useKeyboardAnimation = () => {
31
31
  progress.value = e.progress;
32
32
  height.value = e.height;
33
33
  },
34
+ onInteractive: e => {
35
+ "worklet";
36
+
37
+ progress.value = e.progress;
38
+ height.value = e.height;
39
+ },
34
40
  onEnd: e => {
35
41
  "worklet";
36
42
 
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNativeReanimated","require","_context","_hooks","useKeyboardAnimation","reanimated","useKeyboardContext","heightWhenOpened","useSharedValue","height","value","progress","isClosed","useKeyboardHandler","onStart","e","onMove","onEnd","exports"],"sources":["hooks.ts"],"sourcesContent":["import { useSharedValue } from \"react-native-reanimated\";\n\nimport { useKeyboardContext } from \"../../context\";\nimport { useKeyboardHandler } from \"../../hooks\";\n\nexport const useKeyboardAnimation = () => {\n const { reanimated } = useKeyboardContext();\n const heightWhenOpened = useSharedValue(-reanimated.height.value);\n const height = useSharedValue(-reanimated.height.value);\n const progress = useSharedValue(reanimated.progress.value);\n const isClosed = useSharedValue(reanimated.progress.value === 0);\n\n useKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n if (e.height > 0) {\n // eslint-disable-next-line react-compiler/react-compiler\n isClosed.value = false;\n heightWhenOpened.value = e.height;\n }\n },\n onMove: (e) => {\n \"worklet\";\n\n progress.value = e.progress;\n height.value = e.height;\n },\n onEnd: (e) => {\n \"worklet\";\n\n isClosed.value = e.height === 0;\n\n height.value = e.height;\n progress.value = e.progress;\n },\n },\n [],\n );\n\n return { height, progress, heightWhenOpened, isClosed };\n};\n"],"mappings":";;;;;;AAAA,IAAAA,sBAAA,GAAAC,OAAA;AAEA,IAAAC,QAAA,GAAAD,OAAA;AACA,IAAAE,MAAA,GAAAF,OAAA;AAEO,MAAMG,oBAAoB,GAAGA,CAAA,KAAM;EACxC,MAAM;IAAEC;EAAW,CAAC,GAAG,IAAAC,2BAAkB,EAAC,CAAC;EAC3C,MAAMC,gBAAgB,GAAG,IAAAC,qCAAc,EAAC,CAACH,UAAU,CAACI,MAAM,CAACC,KAAK,CAAC;EACjE,MAAMD,MAAM,GAAG,IAAAD,qCAAc,EAAC,CAACH,UAAU,CAACI,MAAM,CAACC,KAAK,CAAC;EACvD,MAAMC,QAAQ,GAAG,IAAAH,qCAAc,EAACH,UAAU,CAACM,QAAQ,CAACD,KAAK,CAAC;EAC1D,MAAME,QAAQ,GAAG,IAAAJ,qCAAc,EAACH,UAAU,CAACM,QAAQ,CAACD,KAAK,KAAK,CAAC,CAAC;EAEhE,IAAAG,yBAAkB,EAChB;IACEC,OAAO,EAAGC,CAAC,IAAK;MACd,SAAS;;MAET,IAAIA,CAAC,CAACN,MAAM,GAAG,CAAC,EAAE;QAChB;QACAG,QAAQ,CAACF,KAAK,GAAG,KAAK;QACtBH,gBAAgB,CAACG,KAAK,GAAGK,CAAC,CAACN,MAAM;MACnC;IACF,CAAC;IACDO,MAAM,EAAGD,CAAC,IAAK;MACb,SAAS;;MAETJ,QAAQ,CAACD,KAAK,GAAGK,CAAC,CAACJ,QAAQ;MAC3BF,MAAM,CAACC,KAAK,GAAGK,CAAC,CAACN,MAAM;IACzB,CAAC;IACDQ,KAAK,EAAGF,CAAC,IAAK;MACZ,SAAS;;MAETH,QAAQ,CAACF,KAAK,GAAGK,CAAC,CAACN,MAAM,KAAK,CAAC;MAE/BA,MAAM,CAACC,KAAK,GAAGK,CAAC,CAACN,MAAM;MACvBE,QAAQ,CAACD,KAAK,GAAGK,CAAC,CAACJ,QAAQ;IAC7B;EACF,CAAC,EACD,EACF,CAAC;EAED,OAAO;IAAEF,MAAM;IAAEE,QAAQ;IAAEJ,gBAAgB;IAAEK;EAAS,CAAC;AACzD,CAAC;AAACM,OAAA,CAAAd,oBAAA,GAAAA,oBAAA","ignoreList":[]}
1
+ {"version":3,"names":["_reactNativeReanimated","require","_context","_hooks","useKeyboardAnimation","reanimated","useKeyboardContext","heightWhenOpened","useSharedValue","height","value","progress","isClosed","useKeyboardHandler","onStart","e","onMove","onInteractive","onEnd","exports"],"sources":["hooks.ts"],"sourcesContent":["import { useSharedValue } from \"react-native-reanimated\";\n\nimport { useKeyboardContext } from \"../../context\";\nimport { useKeyboardHandler } from \"../../hooks\";\n\nexport const useKeyboardAnimation = () => {\n const { reanimated } = useKeyboardContext();\n const heightWhenOpened = useSharedValue(-reanimated.height.value);\n const height = useSharedValue(-reanimated.height.value);\n const progress = useSharedValue(reanimated.progress.value);\n const isClosed = useSharedValue(reanimated.progress.value === 0);\n\n useKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n if (e.height > 0) {\n // eslint-disable-next-line react-compiler/react-compiler\n isClosed.value = false;\n heightWhenOpened.value = e.height;\n }\n },\n onMove: (e) => {\n \"worklet\";\n\n progress.value = e.progress;\n height.value = e.height;\n },\n onInteractive: (e) => {\n \"worklet\";\n\n progress.value = e.progress;\n height.value = e.height;\n },\n onEnd: (e) => {\n \"worklet\";\n\n isClosed.value = e.height === 0;\n\n height.value = e.height;\n progress.value = e.progress;\n },\n },\n [],\n );\n\n return { height, progress, heightWhenOpened, isClosed };\n};\n"],"mappings":";;;;;;AAAA,IAAAA,sBAAA,GAAAC,OAAA;AAEA,IAAAC,QAAA,GAAAD,OAAA;AACA,IAAAE,MAAA,GAAAF,OAAA;AAEO,MAAMG,oBAAoB,GAAGA,CAAA,KAAM;EACxC,MAAM;IAAEC;EAAW,CAAC,GAAG,IAAAC,2BAAkB,EAAC,CAAC;EAC3C,MAAMC,gBAAgB,GAAG,IAAAC,qCAAc,EAAC,CAACH,UAAU,CAACI,MAAM,CAACC,KAAK,CAAC;EACjE,MAAMD,MAAM,GAAG,IAAAD,qCAAc,EAAC,CAACH,UAAU,CAACI,MAAM,CAACC,KAAK,CAAC;EACvD,MAAMC,QAAQ,GAAG,IAAAH,qCAAc,EAACH,UAAU,CAACM,QAAQ,CAACD,KAAK,CAAC;EAC1D,MAAME,QAAQ,GAAG,IAAAJ,qCAAc,EAACH,UAAU,CAACM,QAAQ,CAACD,KAAK,KAAK,CAAC,CAAC;EAEhE,IAAAG,yBAAkB,EAChB;IACEC,OAAO,EAAGC,CAAC,IAAK;MACd,SAAS;;MAET,IAAIA,CAAC,CAACN,MAAM,GAAG,CAAC,EAAE;QAChB;QACAG,QAAQ,CAACF,KAAK,GAAG,KAAK;QACtBH,gBAAgB,CAACG,KAAK,GAAGK,CAAC,CAACN,MAAM;MACnC;IACF,CAAC;IACDO,MAAM,EAAGD,CAAC,IAAK;MACb,SAAS;;MAETJ,QAAQ,CAACD,KAAK,GAAGK,CAAC,CAACJ,QAAQ;MAC3BF,MAAM,CAACC,KAAK,GAAGK,CAAC,CAACN,MAAM;IACzB,CAAC;IACDQ,aAAa,EAAGF,CAAC,IAAK;MACpB,SAAS;;MAETJ,QAAQ,CAACD,KAAK,GAAGK,CAAC,CAACJ,QAAQ;MAC3BF,MAAM,CAACC,KAAK,GAAGK,CAAC,CAACN,MAAM;IACzB,CAAC;IACDS,KAAK,EAAGH,CAAC,IAAK;MACZ,SAAS;;MAETH,QAAQ,CAACF,KAAK,GAAGK,CAAC,CAACN,MAAM,KAAK,CAAC;MAE/BA,MAAM,CAACC,KAAK,GAAGK,CAAC,CAACN,MAAM;MACvBE,QAAQ,CAACD,KAAK,GAAGK,CAAC,CAACJ,QAAQ;IAC7B;EACF,CAAC,EACD,EACF,CAAC;EAED,OAAO;IAAEF,MAAM;IAAEE,QAAQ;IAAEJ,gBAAgB;IAAEK;EAAS,CAAC;AACzD,CAAC;AAACO,OAAA,CAAAf,oBAAA,GAAAA,oBAAA","ignoreList":[]}
@@ -25,6 +25,12 @@ export const useKeyboardAnimation = () => {
25
25
  progress.value = e.progress;
26
26
  height.value = e.height;
27
27
  },
28
+ onInteractive: e => {
29
+ "worklet";
30
+
31
+ progress.value = e.progress;
32
+ height.value = e.height;
33
+ },
28
34
  onEnd: e => {
29
35
  "worklet";
30
36
 
@@ -1 +1 @@
1
- {"version":3,"names":["useSharedValue","useKeyboardContext","useKeyboardHandler","useKeyboardAnimation","reanimated","heightWhenOpened","height","value","progress","isClosed","onStart","e","onMove","onEnd"],"sources":["hooks.ts"],"sourcesContent":["import { useSharedValue } from \"react-native-reanimated\";\n\nimport { useKeyboardContext } from \"../../context\";\nimport { useKeyboardHandler } from \"../../hooks\";\n\nexport const useKeyboardAnimation = () => {\n const { reanimated } = useKeyboardContext();\n const heightWhenOpened = useSharedValue(-reanimated.height.value);\n const height = useSharedValue(-reanimated.height.value);\n const progress = useSharedValue(reanimated.progress.value);\n const isClosed = useSharedValue(reanimated.progress.value === 0);\n\n useKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n if (e.height > 0) {\n // eslint-disable-next-line react-compiler/react-compiler\n isClosed.value = false;\n heightWhenOpened.value = e.height;\n }\n },\n onMove: (e) => {\n \"worklet\";\n\n progress.value = e.progress;\n height.value = e.height;\n },\n onEnd: (e) => {\n \"worklet\";\n\n isClosed.value = e.height === 0;\n\n height.value = e.height;\n progress.value = e.progress;\n },\n },\n [],\n );\n\n return { height, progress, heightWhenOpened, isClosed };\n};\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,yBAAyB;AAExD,SAASC,kBAAkB,QAAQ,eAAe;AAClD,SAASC,kBAAkB,QAAQ,aAAa;AAEhD,OAAO,MAAMC,oBAAoB,GAAGA,CAAA,KAAM;EACxC,MAAM;IAAEC;EAAW,CAAC,GAAGH,kBAAkB,CAAC,CAAC;EAC3C,MAAMI,gBAAgB,GAAGL,cAAc,CAAC,CAACI,UAAU,CAACE,MAAM,CAACC,KAAK,CAAC;EACjE,MAAMD,MAAM,GAAGN,cAAc,CAAC,CAACI,UAAU,CAACE,MAAM,CAACC,KAAK,CAAC;EACvD,MAAMC,QAAQ,GAAGR,cAAc,CAACI,UAAU,CAACI,QAAQ,CAACD,KAAK,CAAC;EAC1D,MAAME,QAAQ,GAAGT,cAAc,CAACI,UAAU,CAACI,QAAQ,CAACD,KAAK,KAAK,CAAC,CAAC;EAEhEL,kBAAkB,CAChB;IACEQ,OAAO,EAAGC,CAAC,IAAK;MACd,SAAS;;MAET,IAAIA,CAAC,CAACL,MAAM,GAAG,CAAC,EAAE;QAChB;QACAG,QAAQ,CAACF,KAAK,GAAG,KAAK;QACtBF,gBAAgB,CAACE,KAAK,GAAGI,CAAC,CAACL,MAAM;MACnC;IACF,CAAC;IACDM,MAAM,EAAGD,CAAC,IAAK;MACb,SAAS;;MAETH,QAAQ,CAACD,KAAK,GAAGI,CAAC,CAACH,QAAQ;MAC3BF,MAAM,CAACC,KAAK,GAAGI,CAAC,CAACL,MAAM;IACzB,CAAC;IACDO,KAAK,EAAGF,CAAC,IAAK;MACZ,SAAS;;MAETF,QAAQ,CAACF,KAAK,GAAGI,CAAC,CAACL,MAAM,KAAK,CAAC;MAE/BA,MAAM,CAACC,KAAK,GAAGI,CAAC,CAACL,MAAM;MACvBE,QAAQ,CAACD,KAAK,GAAGI,CAAC,CAACH,QAAQ;IAC7B;EACF,CAAC,EACD,EACF,CAAC;EAED,OAAO;IAAEF,MAAM;IAAEE,QAAQ;IAAEH,gBAAgB;IAAEI;EAAS,CAAC;AACzD,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["useSharedValue","useKeyboardContext","useKeyboardHandler","useKeyboardAnimation","reanimated","heightWhenOpened","height","value","progress","isClosed","onStart","e","onMove","onInteractive","onEnd"],"sources":["hooks.ts"],"sourcesContent":["import { useSharedValue } from \"react-native-reanimated\";\n\nimport { useKeyboardContext } from \"../../context\";\nimport { useKeyboardHandler } from \"../../hooks\";\n\nexport const useKeyboardAnimation = () => {\n const { reanimated } = useKeyboardContext();\n const heightWhenOpened = useSharedValue(-reanimated.height.value);\n const height = useSharedValue(-reanimated.height.value);\n const progress = useSharedValue(reanimated.progress.value);\n const isClosed = useSharedValue(reanimated.progress.value === 0);\n\n useKeyboardHandler(\n {\n onStart: (e) => {\n \"worklet\";\n\n if (e.height > 0) {\n // eslint-disable-next-line react-compiler/react-compiler\n isClosed.value = false;\n heightWhenOpened.value = e.height;\n }\n },\n onMove: (e) => {\n \"worklet\";\n\n progress.value = e.progress;\n height.value = e.height;\n },\n onInteractive: (e) => {\n \"worklet\";\n\n progress.value = e.progress;\n height.value = e.height;\n },\n onEnd: (e) => {\n \"worklet\";\n\n isClosed.value = e.height === 0;\n\n height.value = e.height;\n progress.value = e.progress;\n },\n },\n [],\n );\n\n return { height, progress, heightWhenOpened, isClosed };\n};\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,yBAAyB;AAExD,SAASC,kBAAkB,QAAQ,eAAe;AAClD,SAASC,kBAAkB,QAAQ,aAAa;AAEhD,OAAO,MAAMC,oBAAoB,GAAGA,CAAA,KAAM;EACxC,MAAM;IAAEC;EAAW,CAAC,GAAGH,kBAAkB,CAAC,CAAC;EAC3C,MAAMI,gBAAgB,GAAGL,cAAc,CAAC,CAACI,UAAU,CAACE,MAAM,CAACC,KAAK,CAAC;EACjE,MAAMD,MAAM,GAAGN,cAAc,CAAC,CAACI,UAAU,CAACE,MAAM,CAACC,KAAK,CAAC;EACvD,MAAMC,QAAQ,GAAGR,cAAc,CAACI,UAAU,CAACI,QAAQ,CAACD,KAAK,CAAC;EAC1D,MAAME,QAAQ,GAAGT,cAAc,CAACI,UAAU,CAACI,QAAQ,CAACD,KAAK,KAAK,CAAC,CAAC;EAEhEL,kBAAkB,CAChB;IACEQ,OAAO,EAAGC,CAAC,IAAK;MACd,SAAS;;MAET,IAAIA,CAAC,CAACL,MAAM,GAAG,CAAC,EAAE;QAChB;QACAG,QAAQ,CAACF,KAAK,GAAG,KAAK;QACtBF,gBAAgB,CAACE,KAAK,GAAGI,CAAC,CAACL,MAAM;MACnC;IACF,CAAC;IACDM,MAAM,EAAGD,CAAC,IAAK;MACb,SAAS;;MAETH,QAAQ,CAACD,KAAK,GAAGI,CAAC,CAACH,QAAQ;MAC3BF,MAAM,CAACC,KAAK,GAAGI,CAAC,CAACL,MAAM;IACzB,CAAC;IACDO,aAAa,EAAGF,CAAC,IAAK;MACpB,SAAS;;MAETH,QAAQ,CAACD,KAAK,GAAGI,CAAC,CAACH,QAAQ;MAC3BF,MAAM,CAACC,KAAK,GAAGI,CAAC,CAACL,MAAM;IACzB,CAAC;IACDQ,KAAK,EAAGH,CAAC,IAAK;MACZ,SAAS;;MAETF,QAAQ,CAACF,KAAK,GAAGI,CAAC,CAACL,MAAM,KAAK,CAAC;MAE/BA,MAAM,CAACC,KAAK,GAAGI,CAAC,CAACL,MAAM;MACvBE,QAAQ,CAACD,KAAK,GAAGI,CAAC,CAACH,QAAQ;IAC7B;EACF,CAAC,EACD,EACF,CAAC;EAED,OAAO;IAAEF,MAAM;IAAEE,QAAQ;IAAEH,gBAAgB;IAAEI;EAAS,CAAC;AACzD,CAAC","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-keyboard-controller",
3
- "version": "1.14.0",
3
+ "version": "1.14.1",
4
4
  "description": "Keyboard manager which works in identical way on both iOS and Android",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -27,6 +27,12 @@ export const useKeyboardAnimation = () => {
27
27
  progress.value = e.progress;
28
28
  height.value = e.height;
29
29
  },
30
+ onInteractive: (e) => {
31
+ "worklet";
32
+
33
+ progress.value = e.progress;
34
+ height.value = e.height;
35
+ },
30
36
  onEnd: (e) => {
31
37
  "worklet";
32
38