react-native-keyboard-controller 1.14.0 → 1.14.2

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 (24) hide show
  1. package/android/src/main/java/com/reactnativekeyboardcontroller/constants/Keyboard.kt +7 -0
  2. package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputLayoutChangedEvent.kt +5 -1
  3. package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputSelectionChangedEvent.kt +5 -1
  4. package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputTextChangedEvent.kt +5 -1
  5. package/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt +18 -2
  6. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +45 -17
  7. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +11 -7
  8. package/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt +32 -4
  9. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/StatusBarManagerCompatModuleImpl.kt +7 -2
  10. package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +5 -1
  11. package/ios/{core → animations}/KeyboardAnimation.swift +1 -0
  12. package/ios/{core → animations}/SpringAnimation.swift +1 -1
  13. package/ios/{core → animations}/TimingAnimation.swift +21 -20
  14. package/ios/extensions/UIApplication.swift +17 -1
  15. package/ios/extensions/UIView.swift +28 -1
  16. package/ios/extensions/UIWindow.swift +5 -2
  17. package/ios/observers/FocusedInputObserver.swift +4 -4
  18. package/ios/views/OverKeyboardViewManager.mm +17 -0
  19. package/lib/commonjs/components/KeyboardAvoidingView/hooks.js +6 -0
  20. package/lib/commonjs/components/KeyboardAvoidingView/hooks.js.map +1 -1
  21. package/lib/module/components/KeyboardAvoidingView/hooks.js +6 -0
  22. package/lib/module/components/KeyboardAvoidingView/hooks.js.map +1 -1
  23. package/package.json +1 -1
  24. package/src/components/KeyboardAvoidingView/hooks.ts +6 -0
@@ -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
+ }
@@ -20,7 +20,7 @@ class FocusedInputLayoutChangedEvent(
20
20
  viewId: Int,
21
21
  private val event: FocusedInputLayoutChangedEventData,
22
22
  ) : Event<FocusedInputLayoutChangedEvent>(surfaceId, viewId) {
23
- override fun getEventName() = "topFocusedInputLayoutChanged"
23
+ override fun getEventName() = EVENT_NAME
24
24
 
25
25
  // All events for a given view can be coalesced
26
26
  override fun getCoalescingKey(): Short = 0
@@ -41,4 +41,8 @@ class FocusedInputLayoutChangedEvent(
41
41
  },
42
42
  )
43
43
  }
44
+
45
+ companion object {
46
+ const val EVENT_NAME = "topFocusedInputLayoutChanged"
47
+ }
44
48
  }
@@ -19,7 +19,7 @@ class FocusedInputSelectionChangedEvent(
19
19
  viewId: Int,
20
20
  private val event: FocusedInputSelectionChangedEventData,
21
21
  ) : Event<FocusedInputSelectionChangedEvent>(surfaceId, viewId) {
22
- override fun getEventName() = "topFocusedInputSelectionChanged"
22
+ override fun getEventName() = EVENT_NAME
23
23
 
24
24
  // All events for a given view can be coalesced
25
25
  override fun getCoalescingKey(): Short = 0
@@ -49,4 +49,8 @@ class FocusedInputSelectionChangedEvent(
49
49
  },
50
50
  )
51
51
  }
52
+
53
+ companion object {
54
+ const val EVENT_NAME = "topFocusedInputSelectionChanged"
55
+ }
52
56
  }
@@ -9,7 +9,7 @@ class FocusedInputTextChangedEvent(
9
9
  viewId: Int,
10
10
  private val text: String,
11
11
  ) : Event<FocusedInputTextChangedEvent>(surfaceId, viewId) {
12
- override fun getEventName() = "topFocusedInputTextChanged"
12
+ override fun getEventName() = EVENT_NAME
13
13
 
14
14
  // All events for a given view can be coalesced
15
15
  override fun getCoalescingKey(): Short = 0
@@ -18,4 +18,8 @@ class FocusedInputTextChangedEvent(
18
18
  Arguments.createMap().apply {
19
19
  putString("text", text)
20
20
  }
21
+
22
+ companion object {
23
+ const val EVENT_NAME = "topFocusedInputTextChanged"
24
+ }
21
25
  }
@@ -8,13 +8,13 @@ import com.facebook.react.uimanager.events.Event
8
8
  class KeyboardTransitionEvent(
9
9
  surfaceId: Int,
10
10
  viewId: Int,
11
- private val event: String,
11
+ private val event: EventName,
12
12
  private val height: Double,
13
13
  private val progress: Double,
14
14
  private val duration: Int,
15
15
  private val target: Int,
16
16
  ) : Event<KeyboardTransitionEvent>(surfaceId, viewId) {
17
- override fun getEventName() = event
17
+ override fun getEventName() = event.value
18
18
 
19
19
  // All events for a given view can be coalesced?
20
20
  override fun getCoalescingKey(): Short = 0
@@ -26,4 +26,20 @@ class KeyboardTransitionEvent(
26
26
  putInt("duration", duration)
27
27
  putInt("target", target)
28
28
  }
29
+
30
+ companion object {
31
+ enum class EventName(
32
+ val value: String,
33
+ ) {
34
+ Move("topKeyboardMove"),
35
+ Start("topKeyboardMoveStart"),
36
+ End("topKeyboardMoveEnd"),
37
+ Interactive("topKeyboardMoveInteractive"),
38
+ }
39
+
40
+ val Move = EventName.Move
41
+ val Start = EventName.Start
42
+ val End = EventName.End
43
+ val Interactive = EventName.Interactive
44
+ }
29
45
  }
@@ -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 =
@@ -69,7 +79,7 @@ class KeyboardAnimationCallback(
69
79
  KeyboardTransitionEvent(
70
80
  surfaceId,
71
81
  eventPropagationView.id,
72
- "topKeyboardMoveStart",
82
+ KeyboardTransitionEvent.Start,
73
83
  this.persistentKeyboardHeight,
74
84
  1.0,
75
85
  0,
@@ -81,7 +91,7 @@ class KeyboardAnimationCallback(
81
91
  KeyboardTransitionEvent(
82
92
  surfaceId,
83
93
  eventPropagationView.id,
84
- "topKeyboardMoveEnd",
94
+ KeyboardTransitionEvent.End,
85
95
  this.persistentKeyboardHeight,
86
96
  1.0,
87
97
  0,
@@ -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
 
@@ -193,7 +203,7 @@ class KeyboardAnimationCallback(
193
203
  KeyboardTransitionEvent(
194
204
  surfaceId,
195
205
  eventPropagationView.id,
196
- "topKeyboardMoveStart",
206
+ KeyboardTransitionEvent.Start,
197
207
  keyboardHeight,
198
208
  if (!isKeyboardVisible) 0.0 else 1.0,
199
209
  duration,
@@ -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)
@@ -242,7 +258,12 @@ class KeyboardAnimationCallback(
242
258
  "DiffY: $diffY $height $progress ${InteractiveKeyboardProvider.isInteractive} $viewTagFocused",
243
259
  )
244
260
 
245
- val event = if (InteractiveKeyboardProvider.isInteractive) "topKeyboardMoveInteractive" else "topKeyboardMove"
261
+ val event =
262
+ if (InteractiveKeyboardProvider.isInteractive) {
263
+ KeyboardTransitionEvent.Interactive
264
+ } else {
265
+ KeyboardTransitionEvent.Move
266
+ }
246
267
  context.dispatchEvent(
247
268
  eventPropagationView.id,
248
269
  KeyboardTransitionEvent(
@@ -262,7 +283,7 @@ class KeyboardAnimationCallback(
262
283
  override fun onEnd(animation: WindowInsetsAnimationCompat) {
263
284
  super.onEnd(animation)
264
285
 
265
- if (!animation.isKeyboardAnimation) {
286
+ if (!animation.isKeyboardAnimation || isSuspended) {
266
287
  return
267
288
  }
268
289
 
@@ -299,7 +320,7 @@ class KeyboardAnimationCallback(
299
320
  KeyboardTransitionEvent(
300
321
  surfaceId,
301
322
  eventPropagationView.id,
302
- "topKeyboardMoveEnd",
323
+ KeyboardTransitionEvent.End,
303
324
  keyboardHeight,
304
325
  if (!isKeyboardVisible) 0.0 else 1.0,
305
326
  duration,
@@ -311,10 +332,13 @@ class KeyboardAnimationCallback(
311
332
  duration = 0
312
333
  }
313
334
 
314
- fun syncKeyboardPosition() {
315
- val keyboardHeight = getCurrentKeyboardHeight()
335
+ fun syncKeyboardPosition(
336
+ height: Double? = null,
337
+ isVisible: Boolean? = null,
338
+ ) {
339
+ val keyboardHeight = height ?: getCurrentKeyboardHeight()
316
340
  // update internal state
317
- isKeyboardVisible = isKeyboardVisible()
341
+ isKeyboardVisible = isVisible ?: isKeyboardVisible()
318
342
  prevKeyboardHeight = keyboardHeight
319
343
  isTransitioning = false
320
344
  duration = 0
@@ -324,7 +348,7 @@ class KeyboardAnimationCallback(
324
348
  getEventParams(keyboardHeight),
325
349
  )
326
350
  // dispatch `onMove` to update RN animated value and `onEnd` to indicate that transition finished
327
- listOf("topKeyboardMove", "topKeyboardMoveEnd").forEach { eventName ->
351
+ listOf(KeyboardTransitionEvent.Move, KeyboardTransitionEvent.End).forEach { eventName ->
328
352
  context.dispatchEvent(
329
353
  eventPropagationView.id,
330
354
  KeyboardTransitionEvent(
@@ -352,7 +376,11 @@ class KeyboardAnimationCallback(
352
376
  duration = 0
353
377
 
354
378
  context.emitEvent("KeyboardController::keyboardWillShow", getEventParams(keyboardHeight))
355
- listOf("topKeyboardMoveStart", "topKeyboardMove", "topKeyboardMoveEnd").forEach { eventName ->
379
+ listOf(
380
+ KeyboardTransitionEvent.Start,
381
+ KeyboardTransitionEvent.Move,
382
+ KeyboardTransitionEvent.End,
383
+ ).forEach { eventName ->
356
384
  context.dispatchEvent(
357
385
  eventPropagationView.id,
358
386
  KeyboardTransitionEvent(
@@ -3,6 +3,10 @@ package com.reactnativekeyboardcontroller.managers
3
3
  import com.facebook.react.bridge.ReactApplicationContext
4
4
  import com.facebook.react.common.MapBuilder
5
5
  import com.facebook.react.uimanager.ThemedReactContext
6
+ import com.reactnativekeyboardcontroller.events.FocusedInputLayoutChangedEvent
7
+ import com.reactnativekeyboardcontroller.events.FocusedInputSelectionChangedEvent
8
+ import com.reactnativekeyboardcontroller.events.FocusedInputTextChangedEvent
9
+ import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent
6
10
  import com.reactnativekeyboardcontroller.views.EdgeToEdgeReactViewGroup
7
11
 
8
12
  @Suppress("detekt:UnusedPrivateProperty")
@@ -36,19 +40,19 @@ class KeyboardControllerViewManagerImpl(
36
40
  fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
37
41
  val map: MutableMap<String, Any> =
38
42
  MapBuilder.of(
39
- "topKeyboardMove",
43
+ KeyboardTransitionEvent.Move.value,
40
44
  MapBuilder.of("registrationName", "onKeyboardMove"),
41
- "topKeyboardMoveStart",
45
+ KeyboardTransitionEvent.Start.value,
42
46
  MapBuilder.of("registrationName", "onKeyboardMoveStart"),
43
- "topKeyboardMoveEnd",
47
+ KeyboardTransitionEvent.End.value,
44
48
  MapBuilder.of("registrationName", "onKeyboardMoveEnd"),
45
- "topKeyboardMoveInteractive",
49
+ KeyboardTransitionEvent.Interactive.value,
46
50
  MapBuilder.of("registrationName", "onKeyboardMoveInteractive"),
47
- "topFocusedInputLayoutChanged",
51
+ FocusedInputLayoutChangedEvent.EVENT_NAME,
48
52
  MapBuilder.of("registrationName", "onFocusedInputLayoutChanged"),
49
- "topFocusedInputTextChanged",
53
+ FocusedInputTextChangedEvent.EVENT_NAME,
50
54
  MapBuilder.of("registrationName", "onFocusedInputTextChanged"),
51
- "topFocusedInputSelectionChanged",
55
+ FocusedInputSelectionChangedEvent.EVENT_NAME,
52
56
  MapBuilder.of("registrationName", "onFocusedInputSelectionChanged"),
53
57
  )
54
58
 
@@ -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,8 +9,24 @@ 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
- base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
29
+ base: UIViewController? = UIApplication.shared.activeWindow?.rootViewController
14
30
  ) -> UIViewController? {
15
31
  if let nav = base as? UINavigationController {
16
32
  return topViewController(base: nav.visibleViewController)
@@ -11,9 +11,29 @@ import UIKit
11
11
 
12
12
  public extension UIView {
13
13
  var globalFrame: CGRect? {
14
- let rootView = UIApplication.shared.keyWindow?.rootViewController?.view
14
+ let rootView = UIApplication.shared.activeWindow?.rootViewController?.view
15
15
  return superview?.convert(frame, to: rootView)
16
16
  }
17
+
18
+ func isVisibleInHierarchy(initial: Bool = true) -> Bool {
19
+ guard let window = window else {
20
+ return false
21
+ }
22
+ if isHidden || alpha == 0.0 {
23
+ return false
24
+ }
25
+ if superview === window {
26
+ return true
27
+ } else if let superview = superview {
28
+ if initial, frame.minY >= superview.frame.height {
29
+ return false
30
+ } else {
31
+ return superview.isVisibleInHierarchy(initial: false)
32
+ }
33
+ } else {
34
+ return false
35
+ }
36
+ }
17
37
  }
18
38
 
19
39
  public extension Optional where Wrapped == UIView {
@@ -32,4 +52,11 @@ public extension Optional where Wrapped == UIView {
32
52
 
33
53
  return (position, frameY)
34
54
  }
55
+
56
+ func isVisibleInHierarchy(initial: Bool = true) -> Bool {
57
+ guard let view = self else {
58
+ return false
59
+ }
60
+ return view.isVisibleInHierarchy(initial: initial)
61
+ }
35
62
  }
@@ -37,8 +37,11 @@ public extension UIWindow {
37
37
  }
38
38
 
39
39
  func getTopWindow() -> UIWindow? {
40
- // Return the keyboard window if it's available, otherwise return the last window
41
- return keyboardWindow ?? UIApplication.shared.windows.last
40
+ let keyboardView = KeyboardView.find()
41
+ // return the keyboard window if it's available and keyboard is visible, otherwise return the last window
42
+ return (keyboardWindow != nil && keyboardView.isVisibleInHierarchy())
43
+ ? keyboardWindow
44
+ : UIApplication.shared.activeWindow
42
45
  }
43
46
  }
44
47
 
@@ -204,10 +204,10 @@ public class FocusedInputObserver: NSObject {
204
204
  }
205
205
 
206
206
  private func substituteDelegateBack(_ input: UIResponder?) {
207
- if let textField = input as? UITextField {
208
- textField.delegate = delegate.activeDelegate as? UITextFieldDelegate
209
- } else if let textView = input as? UITextView {
210
- (textView as? RCTUITextView)?.setForceDelegate(delegate.activeDelegate as? UITextViewDelegate)
207
+ if let textField = input as? UITextField, let oldDelegate = delegate.activeDelegate as? UITextFieldDelegate {
208
+ textField.delegate = oldDelegate
209
+ } else if let textView = input as? UITextView, let oldDelegate = delegate.activeDelegate as? UITextViewDelegate {
210
+ (textView as? RCTUITextView)?.setForceDelegate(oldDelegate)
211
211
  }
212
212
  }
213
213
 
@@ -102,10 +102,27 @@ RCT_EXPORT_VIEW_PROPERTY(visible, BOOL)
102
102
  _touchHandler = [[RCTTouchHandler alloc] initWithBridge:bridge];
103
103
  _contentView = [[UIView alloc] initWithFrame:CGRectZero];
104
104
  }
105
+ [[NSNotificationCenter defaultCenter] addObserver:self
106
+ selector:@selector(hide)
107
+ name:RCTJavaScriptWillStartLoadingNotification
108
+ object:nil];
105
109
  return self;
106
110
  }
107
111
  #endif
108
112
 
113
+ - (void)dealloc
114
+ {
115
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
116
+ }
117
+
118
+ // MARK: lifecycle methods
119
+ - (void)didMoveToSuperview
120
+ {
121
+ if (self.superview == nil) {
122
+ [self hide];
123
+ }
124
+ }
125
+
109
126
  // MARK: touch handling
110
127
  - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
111
128
  {
@@ -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.2",
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