react-native-keyboard-controller 1.13.4 → 1.14.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 (105) hide show
  1. package/README.md +1 -0
  2. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +5 -3
  3. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +19 -20
  4. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +22 -12
  5. package/android/src/fabric/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt +40 -0
  6. package/android/src/fabric/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +7 -3
  7. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +33 -27
  8. package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputLayoutChangedEvent.kt +16 -15
  9. package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputSelectionChangedEvent.kt +25 -24
  10. package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputTextChangedEvent.kt +4 -3
  11. package/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt +7 -6
  12. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/Context.kt +38 -0
  13. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt +78 -58
  14. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +9 -4
  15. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt +10 -3
  16. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt +10 -8
  17. package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/KeyboardAnimationController.kt +65 -60
  18. package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/Interpolator.kt +6 -1
  19. package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/IosInterpolator.kt +4 -2
  20. package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/LinearInterpolator.kt +1 -3
  21. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt +62 -58
  22. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +47 -41
  23. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt +13 -7
  24. package/android/src/main/java/com/reactnativekeyboardcontroller/log/Logger.kt +10 -2
  25. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +35 -24
  26. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardGestureAreaViewManagerImpl.kt +21 -8
  27. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/OverKeyboardViewManagerImpl.kt +27 -0
  28. package/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt +14 -12
  29. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +8 -8
  30. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/StatusBarManagerCompatModuleImpl.kt +7 -2
  31. package/android/src/main/java/com/reactnativekeyboardcontroller/traversal/FocusedInputHolder.kt +1 -3
  32. package/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt +19 -13
  33. package/android/src/main/java/com/reactnativekeyboardcontroller/ui/FrameScheduler.kt +11 -8
  34. package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +22 -17
  35. package/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardGestureAreaReactViewGroup.kt +23 -14
  36. package/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardHostShadowNode.kt +30 -0
  37. package/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardViewGroup.kt +185 -0
  38. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +3 -1
  39. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +19 -10
  40. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +21 -8
  41. package/android/src/paper/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt +33 -0
  42. package/android/src/paper/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +7 -3
  43. package/android/src/test/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigatorTest.kt +30 -21
  44. package/ios/KeyboardController-Bridging-Header.h +1 -0
  45. package/ios/extensions/UIResponder.swift +0 -3
  46. package/ios/extensions/UIWindow.swift +48 -0
  47. package/ios/views/OverKeyboardViewManager.h +29 -0
  48. package/ios/views/OverKeyboardViewManager.mm +220 -0
  49. package/jest/index.js +1 -0
  50. package/lib/commonjs/bindings.js +2 -1
  51. package/lib/commonjs/bindings.js.map +1 -1
  52. package/lib/commonjs/bindings.native.js +2 -1
  53. package/lib/commonjs/bindings.native.js.map +1 -1
  54. package/lib/commonjs/components/KeyboardAwareScrollView/index.js +2 -1
  55. package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
  56. package/lib/commonjs/components/KeyboardToolbar/index.js +5 -3
  57. package/lib/commonjs/components/KeyboardToolbar/index.js.map +1 -1
  58. package/lib/commonjs/index.js +9 -1
  59. package/lib/commonjs/index.js.map +1 -1
  60. package/lib/commonjs/specs/OverKeyboardViewNativeComponent.js +10 -0
  61. package/lib/commonjs/specs/OverKeyboardViewNativeComponent.js.map +1 -0
  62. package/lib/commonjs/types.js.map +1 -1
  63. package/lib/commonjs/views/OverKeyboardView/index.js +43 -0
  64. package/lib/commonjs/views/OverKeyboardView/index.js.map +1 -0
  65. package/lib/commonjs/views/index.js +14 -0
  66. package/lib/commonjs/views/index.js.map +1 -0
  67. package/lib/module/bindings.js +1 -0
  68. package/lib/module/bindings.js.map +1 -1
  69. package/lib/module/bindings.native.js +1 -0
  70. package/lib/module/bindings.native.js.map +1 -1
  71. package/lib/module/components/KeyboardAwareScrollView/index.js +2 -1
  72. package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
  73. package/lib/module/components/KeyboardToolbar/index.js +5 -3
  74. package/lib/module/components/KeyboardToolbar/index.js.map +1 -1
  75. package/lib/module/index.js +1 -0
  76. package/lib/module/index.js.map +1 -1
  77. package/lib/module/specs/OverKeyboardViewNativeComponent.js +3 -0
  78. package/lib/module/specs/OverKeyboardViewNativeComponent.js.map +1 -0
  79. package/lib/module/types.js.map +1 -1
  80. package/lib/module/views/OverKeyboardView/index.js +35 -0
  81. package/lib/module/views/OverKeyboardView/index.js.map +1 -0
  82. package/lib/module/views/index.js +2 -0
  83. package/lib/module/views/index.js.map +1 -0
  84. package/lib/typescript/bindings.d.ts +2 -1
  85. package/lib/typescript/bindings.native.d.ts +2 -1
  86. package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +4 -0
  87. package/lib/typescript/components/KeyboardToolbar/index.d.ts +2 -2
  88. package/lib/typescript/index.d.ts +1 -0
  89. package/lib/typescript/specs/OverKeyboardViewNativeComponent.d.ts +7 -0
  90. package/lib/typescript/types.d.ts +4 -1
  91. package/lib/typescript/views/OverKeyboardView/index.d.ts +5 -0
  92. package/lib/typescript/views/index.d.ts +1 -0
  93. package/package.json +8 -3
  94. package/src/bindings.native.ts +3 -0
  95. package/src/bindings.ts +3 -0
  96. package/src/components/KeyboardAwareScrollView/index.tsx +5 -2
  97. package/src/components/KeyboardToolbar/index.tsx +7 -3
  98. package/src/index.ts +1 -0
  99. package/src/specs/OverKeyboardViewNativeComponent.ts +12 -0
  100. package/src/types.ts +4 -0
  101. package/src/views/OverKeyboardView/index.tsx +43 -0
  102. package/src/views/index.ts +1 -0
  103. package/ios/.clang-format +0 -90
  104. package/ios/.swiftformat +0 -5
  105. package/ios/.swiftlint.yml +0 -14
@@ -18,16 +18,18 @@ fun View.requestApplyInsetsWhenAttached() {
18
18
  requestApplyInsets()
19
19
  } else {
20
20
  // We're not attached to the hierarchy, add a listener to request when we are
21
- addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
22
- override fun onViewAttachedToWindow(v: View) {
23
- v.removeOnAttachStateChangeListener(this)
24
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
25
- v.requestApplyInsets()
21
+ addOnAttachStateChangeListener(
22
+ object : View.OnAttachStateChangeListener {
23
+ override fun onViewAttachedToWindow(v: View) {
24
+ v.removeOnAttachStateChangeListener(this)
25
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
26
+ v.requestApplyInsets()
27
+ }
26
28
  }
27
- }
28
29
 
29
- override fun onViewDetachedFromWindow(v: View) = Unit
30
- })
30
+ override fun onViewDetachedFromWindow(v: View) = Unit
31
+ },
32
+ )
31
33
  }
32
34
  }
33
35
 
@@ -73,7 +73,8 @@ internal class KeyboardAnimationController {
73
73
  }
74
74
 
75
75
  // Keep track of the IME insets, and the IME visibility, at the start of the request
76
- isImeShownAtStart = ViewCompat.getRootWindowInsets(view)
76
+ isImeShownAtStart = ViewCompat
77
+ .getRootWindowInsets(view)
77
78
  ?.isVisible(WindowInsetsCompat.Type.ime()) == true
78
79
 
79
80
  // Create a cancellation signal, which we pass to controlWindowInsetsAnimation() below
@@ -114,7 +115,10 @@ internal class KeyboardAnimationController {
114
115
  * @param view The view which is triggering this request
115
116
  * @param velocityY the velocity of the touch gesture which caused this call
116
117
  */
117
- fun startAndFling(view: View, velocityY: Float) = startControlRequest(view) {
118
+ fun startAndFling(
119
+ view: View,
120
+ velocityY: Float,
121
+ ) = startControlRequest(view) {
118
122
  animateToFinish(velocityY)
119
123
  }
120
124
 
@@ -127,11 +131,12 @@ internal class KeyboardAnimationController {
127
131
  * @return the amount of [dy] consumed by the inset animation, in pixels
128
132
  */
129
133
  fun insetBy(dy: Int): Int {
130
- val controller = insetsAnimationController
131
- ?: throw IllegalStateException(
132
- "Current WindowInsetsAnimationController is null." +
133
- "This should only be called if isAnimationInProgress() returns true",
134
- )
134
+ val controller =
135
+ insetsAnimationController
136
+ ?: throw IllegalStateException(
137
+ "Current WindowInsetsAnimationController is null." +
138
+ "This should only be called if isAnimationInProgress() returns true",
139
+ )
135
140
 
136
141
  InteractiveKeyboardProvider.isInteractive = true
137
142
  // Call updateInsetTo() with the new inset value
@@ -147,11 +152,12 @@ internal class KeyboardAnimationController {
147
152
  * @return the distance moved by the inset animation, in pixels
148
153
  */
149
154
  fun insetTo(inset: Int): Int {
150
- val controller = insetsAnimationController
151
- ?: throw IllegalStateException(
152
- "Current WindowInsetsAnimationController is null." +
153
- "This should only be called if isAnimationInProgress() returns true",
154
- )
155
+ val controller =
156
+ insetsAnimationController
157
+ ?: throw IllegalStateException(
158
+ "Current WindowInsetsAnimationController is null." +
159
+ "This should only be called if isAnimationInProgress() returns true",
160
+ )
155
161
 
156
162
  val hiddenBottom = controller.hiddenStateInsets.bottom
157
163
  val shownBottom = controller.shownStateInsets.bottom
@@ -182,23 +188,17 @@ internal class KeyboardAnimationController {
182
188
  /**
183
189
  * Return `true` if an inset animation is in progress.
184
190
  */
185
- fun isInsetAnimationInProgress(): Boolean {
186
- return insetsAnimationController != null
187
- }
191
+ fun isInsetAnimationInProgress(): Boolean = insetsAnimationController != null
188
192
 
189
193
  /**
190
194
  * Return `true` if an inset animation is currently finishing.
191
195
  */
192
- fun isInsetAnimationFinishing(): Boolean {
193
- return currentSpringAnimation != null
194
- }
196
+ fun isInsetAnimationFinishing(): Boolean = currentSpringAnimation != null
195
197
 
196
198
  /**
197
199
  * Return `true` if a request to control an inset animation is in progress.
198
200
  */
199
- fun isInsetAnimationRequestPending(): Boolean {
200
- return pendingRequestCancellationSignal != null
201
- }
201
+ fun isInsetAnimationRequestPending(): Boolean = pendingRequestCancellationSignal != null
202
202
 
203
203
  /**
204
204
  * Cancel the current [WindowInsetsAnimationControllerCompat]. We immediately finish
@@ -280,10 +280,11 @@ internal class KeyboardAnimationController {
280
280
  when {
281
281
  // If we have a velocity, we can use it's direction to determine
282
282
  // the visibility. Upwards == visible
283
- velocityY != null -> animateImeToVisibility(
284
- visible = velocityY < 0,
285
- velocityY = velocityY,
286
- )
283
+ velocityY != null ->
284
+ animateImeToVisibility(
285
+ visible = velocityY < 0,
286
+ velocityY = velocityY,
287
+ )
287
288
  // The current inset matches either the shown/hidden inset, finish() immediately
288
289
  current == shown -> {
289
290
  InteractiveKeyboardProvider.shown = true
@@ -307,11 +308,12 @@ internal class KeyboardAnimationController {
307
308
  }
308
309
 
309
310
  fun getCurrentKeyboardHeight(): Int {
310
- val controller = insetsAnimationController
311
- ?: throw IllegalStateException(
312
- "Current WindowInsetsAnimationController is null." +
313
- "This should only be called if isAnimationInProgress() returns true",
314
- )
311
+ val controller =
312
+ insetsAnimationController
313
+ ?: throw IllegalStateException(
314
+ "Current WindowInsetsAnimationController is null." +
315
+ "This should only be called if isAnimationInProgress() returns true",
316
+ )
315
317
 
316
318
  return controller.currentInsets.bottom
317
319
  }
@@ -356,37 +358,40 @@ internal class KeyboardAnimationController {
356
358
  velocityY: Float? = null,
357
359
  ) {
358
360
  @Suppress("detekt:UseCheckOrError")
359
- val controller = insetsAnimationController
360
- ?: throw IllegalStateException("Controller should not be null")
361
-
362
- currentSpringAnimation = springAnimationOf(
363
- setter = {
364
- insetTo(it.roundToInt())
365
- },
366
- getter = { controller.currentInsets.bottom.toFloat() },
367
- finalPosition = when {
368
- visible -> controller.shownStateInsets.bottom.toFloat()
369
- else -> controller.hiddenStateInsets.bottom.toFloat()
370
- },
371
- ).withSpringForceProperties {
372
- // Tweak the damping value, to remove any bounciness.
373
- dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
374
- // The stiffness value controls the strength of the spring animation, which
375
- // controls the speed. Medium (the default) is a good value, but feel free to
376
- // play around with this value.
377
- stiffness = SpringForce.STIFFNESS_MEDIUM
378
- }.apply {
379
- if (velocityY != null) {
380
- setStartVelocity(velocityY)
381
- }
382
- addEndListener { anim, _, _, _ ->
383
- if (anim == currentSpringAnimation) {
384
- currentSpringAnimation = null
361
+ val controller =
362
+ insetsAnimationController
363
+ ?: throw IllegalStateException("Controller should not be null")
364
+
365
+ currentSpringAnimation =
366
+ springAnimationOf(
367
+ setter = {
368
+ insetTo(it.roundToInt())
369
+ },
370
+ getter = { controller.currentInsets.bottom.toFloat() },
371
+ finalPosition =
372
+ when {
373
+ visible -> controller.shownStateInsets.bottom.toFloat()
374
+ else -> controller.hiddenStateInsets.bottom.toFloat()
375
+ },
376
+ ).withSpringForceProperties {
377
+ // Tweak the damping value, to remove any bounciness.
378
+ dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
379
+ // The stiffness value controls the strength of the spring animation, which
380
+ // controls the speed. Medium (the default) is a good value, but feel free to
381
+ // play around with this value.
382
+ stiffness = SpringForce.STIFFNESS_MEDIUM
383
+ }.apply {
384
+ if (velocityY != null) {
385
+ setStartVelocity(velocityY)
385
386
  }
386
- // Once the animation has ended, finish the controller
387
- finish()
388
- }
389
- }.also { it.start() }
387
+ addEndListener { anim, _, _, _ ->
388
+ if (anim == currentSpringAnimation) {
389
+ currentSpringAnimation = null
390
+ }
391
+ // Once the animation has ended, finish the controller
392
+ finish()
393
+ }
394
+ }.also { it.start() }
390
395
  }
391
396
  }
392
397
 
@@ -11,5 +11,10 @@ interface Interpolator {
11
11
  * @param offset extra space to the keyboard to activate a gesture
12
12
  * @return the distance the keyboard should be moved from its current location.
13
13
  */
14
- fun interpolate(dy: Int, absoluteFingerPosition: Int, keyboardPosition: Int, offset: Int): Int
14
+ fun interpolate(
15
+ dy: Int,
16
+ absoluteFingerPosition: Int,
17
+ keyboardPosition: Int,
18
+ offset: Int,
19
+ ): Int
15
20
  }
@@ -8,8 +8,10 @@ class IosInterpolator : Interpolator {
8
8
  offset: Int,
9
9
  ): Int {
10
10
  if (
11
- absoluteFingerPosition <= keyboardPosition + offset || // user over scrolled keyboard
12
- dy <= 0 // user scrolls up
11
+ // user over scrolled keyboard
12
+ absoluteFingerPosition <= keyboardPosition + offset ||
13
+ // user scrolls up
14
+ dy <= 0
13
15
  ) {
14
16
  return dy
15
17
  }
@@ -6,7 +6,5 @@ class LinearInterpolator : Interpolator {
6
6
  absoluteFingerPosition: Int,
7
7
  keyboardPosition: Int,
8
8
  offset: Int,
9
- ): Int {
10
- return dy
11
- }
9
+ ): Int = dy
12
10
  }
@@ -25,16 +25,17 @@ import com.reactnativekeyboardcontroller.extensions.screenLocation
25
25
  import com.reactnativekeyboardcontroller.traversal.FocusedInputHolder
26
26
  import com.reactnativekeyboardcontroller.traversal.ViewHierarchyNavigator
27
27
 
28
- val noFocusedInputEvent = FocusedInputLayoutChangedEventData(
29
- x = 0.0,
30
- y = 0.0,
31
- width = 0.0,
32
- height = 0.0,
33
- absoluteX = 0.0,
34
- absoluteY = 0.0,
35
- target = -1,
36
- parentScrollViewTarget = -1,
37
- )
28
+ val noFocusedInputEvent =
29
+ FocusedInputLayoutChangedEventData(
30
+ x = 0.0,
31
+ y = 0.0,
32
+ width = 0.0,
33
+ height = 0.0,
34
+ absoluteX = 0.0,
35
+ absoluteY = 0.0,
36
+ target = -1,
37
+ parentScrollViewTarget = -1,
38
+ )
38
39
 
39
40
  class FocusedInputObserver(
40
41
  val view: View,
@@ -82,50 +83,52 @@ class FocusedInputObserver(
82
83
  FocusedInputSelectionChangedEvent(
83
84
  surfaceId,
84
85
  eventPropagationView.id,
85
- event = FocusedInputSelectionChangedEventData(
86
- target = input.id,
87
- start = start,
88
- end = end,
89
- startX = startX,
90
- startY = startY,
91
- endX = endX,
92
- endY = endY,
93
- ),
86
+ event =
87
+ FocusedInputSelectionChangedEventData(
88
+ target = input.id,
89
+ start = start,
90
+ end = end,
91
+ startX = startX,
92
+ startY = startY,
93
+ endX = endX,
94
+ endY = endY,
95
+ ),
94
96
  ),
95
97
  )
96
98
  }
97
- private val focusListener = OnGlobalFocusChangeListener { oldFocus, newFocus ->
98
- // unfocused or focus was changed
99
- if (newFocus == null || oldFocus != null) {
100
- lastFocusedInput?.removeOnLayoutChangeListener(layoutListener)
101
- lastFocusedInput?.removeTextChangedListener(textWatcher)
102
- selectionSubscription?.invoke()
103
- lastFocusedInput = null
104
- }
105
- if (newFocus is ReactEditText) {
106
- lastFocusedInput = newFocus
107
- newFocus.addOnLayoutChangeListener(layoutListener)
108
- this.syncUpLayout()
109
- textWatcher = newFocus.addOnTextChangedListener(textListener)
110
- selectionSubscription = newFocus.addOnSelectionChangedListener(selectionListener)
111
- FocusedInputHolder.set(newFocus)
99
+ private val focusListener =
100
+ OnGlobalFocusChangeListener { oldFocus, newFocus ->
101
+ // unfocused or focus was changed
102
+ if (newFocus == null || oldFocus != null) {
103
+ lastFocusedInput?.removeOnLayoutChangeListener(layoutListener)
104
+ lastFocusedInput?.removeTextChangedListener(textWatcher)
105
+ selectionSubscription?.invoke()
106
+ lastFocusedInput = null
107
+ }
108
+ if (newFocus is ReactEditText) {
109
+ lastFocusedInput = newFocus
110
+ newFocus.addOnLayoutChangeListener(layoutListener)
111
+ this.syncUpLayout()
112
+ textWatcher = newFocus.addOnTextChangedListener(textListener)
113
+ selectionSubscription = newFocus.addOnSelectionChangedListener(selectionListener)
114
+ FocusedInputHolder.set(newFocus)
112
115
 
113
- val allInputFields = ViewHierarchyNavigator.getAllInputFields(context?.rootView)
114
- val currentIndex = allInputFields.indexOf(newFocus)
116
+ val allInputFields = ViewHierarchyNavigator.getAllInputFields(context?.rootView)
117
+ val currentIndex = allInputFields.indexOf(newFocus)
115
118
 
116
- context.emitEvent(
117
- "KeyboardController::focusDidSet",
118
- Arguments.createMap().apply {
119
- putInt("current", currentIndex)
120
- putInt("count", allInputFields.size)
121
- },
122
- )
119
+ context.emitEvent(
120
+ "KeyboardController::focusDidSet",
121
+ Arguments.createMap().apply {
122
+ putInt("current", currentIndex)
123
+ putInt("count", allInputFields.size)
124
+ },
125
+ )
126
+ }
127
+ // unfocused
128
+ if (newFocus == null) {
129
+ dispatchEventToJS(noFocusedInputEvent)
130
+ }
123
131
  }
124
- // unfocused
125
- if (newFocus == null) {
126
- dispatchEventToJS(noFocusedInputEvent)
127
- }
128
- }
129
132
 
130
133
  init {
131
134
  view.viewTreeObserver.addOnGlobalFocusChangeListener(focusListener)
@@ -135,16 +138,17 @@ class FocusedInputObserver(
135
138
  val input = lastFocusedInput ?: return
136
139
 
137
140
  val (x, y) = input.screenLocation
138
- val event = FocusedInputLayoutChangedEventData(
139
- x = input.x.dp,
140
- y = input.y.dp,
141
- width = input.width.toFloat().dp,
142
- height = input.height.toFloat().dp,
143
- absoluteX = x.toFloat().dp,
144
- absoluteY = y.toFloat().dp,
145
- target = input.id,
146
- parentScrollViewTarget = input.parentScrollViewTarget,
147
- )
141
+ val event =
142
+ FocusedInputLayoutChangedEventData(
143
+ x = input.x.dp,
144
+ y = input.y.dp,
145
+ width = input.width.toFloat().dp,
146
+ height = input.height.toFloat().dp,
147
+ absoluteX = x.toFloat().dp,
148
+ absoluteY = y.toFloat().dp,
149
+ target = input.id,
150
+ parentScrollViewTarget = input.parentScrollViewTarget,
151
+ )
148
152
 
149
153
  dispatchEventToJS(event)
150
154
  }
@@ -38,7 +38,8 @@ class KeyboardAnimationCallback(
38
38
  val view: View,
39
39
  val context: ThemedReactContext?,
40
40
  private val config: KeyboardAnimationCallbackConfig,
41
- ) : WindowInsetsAnimationCompat.Callback(config.dispatchMode), OnApplyWindowInsetsListener {
41
+ ) : WindowInsetsAnimationCompat.Callback(config.dispatchMode),
42
+ OnApplyWindowInsetsListener {
42
43
  private val surfaceId = UIManagerHelper.getSurfaceId(eventPropagationView)
43
44
 
44
45
  // state variables
@@ -51,46 +52,47 @@ class KeyboardAnimationCallback(
51
52
  private var animationsToSkip = hashSetOf<WindowInsetsAnimationCompat>()
52
53
 
53
54
  // listeners
54
- private val focusListener = OnGlobalFocusChangeListener { oldFocus, newFocus ->
55
- if (newFocus is ReactEditText) {
56
- viewTagFocused = newFocus.id
57
-
58
- // keyboard is visible and focus has been changed
59
- if (this.isKeyboardVisible && oldFocus !== null) {
60
- // imitate iOS behavior and send two instant start/end events containing an info about new tag
61
- // 1. onStart/onMove/onEnd can be still dispatched after, if keyboard change size (numeric -> alphabetic type)
62
- // 2. event should be send only when keyboard is visible, since this event arrives earlier -> `tag` will be
63
- // 100% included in onStart/onMove/onEnd life cycles, but triggering onStart/onEnd several time
64
- // can bring breaking changes
65
- context.dispatchEvent(
66
- eventPropagationView.id,
67
- KeyboardTransitionEvent(
68
- surfaceId,
55
+ private val focusListener =
56
+ OnGlobalFocusChangeListener { oldFocus, newFocus ->
57
+ if (newFocus is ReactEditText) {
58
+ viewTagFocused = newFocus.id
59
+
60
+ // keyboard is visible and focus has been changed
61
+ if (this.isKeyboardVisible && oldFocus !== null) {
62
+ // imitate iOS behavior and send two instant start/end events containing an info about new tag
63
+ // 1. onStart/onMove/onEnd can be still dispatched after, if keyboard change size (numeric -> alphabetic type)
64
+ // 2. event should be send only when keyboard is visible, since this event arrives earlier -> `tag` will be
65
+ // 100% included in onStart/onMove/onEnd life cycles, but triggering onStart/onEnd several time
66
+ // can bring breaking changes
67
+ context.dispatchEvent(
69
68
  eventPropagationView.id,
70
- "topKeyboardMoveStart",
71
- this.persistentKeyboardHeight,
72
- 1.0,
73
- 0,
74
- viewTagFocused,
75
- ),
76
- )
77
- context.dispatchEvent(
78
- eventPropagationView.id,
79
- KeyboardTransitionEvent(
80
- surfaceId,
69
+ KeyboardTransitionEvent(
70
+ surfaceId,
71
+ eventPropagationView.id,
72
+ "topKeyboardMoveStart",
73
+ this.persistentKeyboardHeight,
74
+ 1.0,
75
+ 0,
76
+ viewTagFocused,
77
+ ),
78
+ )
79
+ context.dispatchEvent(
81
80
  eventPropagationView.id,
82
- "topKeyboardMoveEnd",
83
- this.persistentKeyboardHeight,
84
- 1.0,
85
- 0,
86
- viewTagFocused,
87
- ),
88
- )
89
- context.emitEvent("KeyboardController::keyboardWillShow", getEventParams(this.persistentKeyboardHeight))
90
- context.emitEvent("KeyboardController::keyboardDidShow", getEventParams(this.persistentKeyboardHeight))
81
+ KeyboardTransitionEvent(
82
+ surfaceId,
83
+ eventPropagationView.id,
84
+ "topKeyboardMoveEnd",
85
+ this.persistentKeyboardHeight,
86
+ 1.0,
87
+ 0,
88
+ viewTagFocused,
89
+ ),
90
+ )
91
+ context.emitEvent("KeyboardController::keyboardWillShow", getEventParams(this.persistentKeyboardHeight))
92
+ context.emitEvent("KeyboardController::keyboardDidShow", getEventParams(this.persistentKeyboardHeight))
93
+ }
91
94
  }
92
95
  }
93
- }
94
96
  private var layoutObserver: FocusedInputObserver? = null
95
97
 
96
98
  init {
@@ -113,7 +115,10 @@ class KeyboardAnimationCallback(
113
115
  * have to implement `onApplyWindowInsets` listener and simulate onStart/onProgress/onEnd
114
116
  * events when keyboard changes its size.
115
117
  */
116
- override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
118
+ override fun onApplyWindowInsets(
119
+ v: View,
120
+ insets: WindowInsetsCompat,
121
+ ): WindowInsetsCompat {
117
122
  val keyboardHeight = getCurrentKeyboardHeight()
118
123
  // when keyboard appears values will be (false && true)
119
124
  // when keyboard disappears values will be (true && false)
@@ -218,9 +223,10 @@ class KeyboardAnimationCallback(
218
223
  if (config.hasTranslucentNavigationBar) {
219
224
  otherInset = Insets.NONE
220
225
  }
221
- val diff = Insets.subtract(typesInset, otherInset).let {
222
- Insets.max(it, Insets.NONE)
223
- }
226
+ val diff =
227
+ Insets.subtract(typesInset, otherInset).let {
228
+ Insets.max(it, Insets.NONE)
229
+ }
224
230
  val diffY = (diff.bottom - diff.top).toFloat()
225
231
  val height = diffY.dp
226
232
 
@@ -8,9 +8,14 @@ import com.reactnativekeyboardcontroller.extensions.content
8
8
  import com.reactnativekeyboardcontroller.extensions.dp
9
9
  import com.reactnativekeyboardcontroller.extensions.emitEvent
10
10
 
11
- data class Dimensions(val width: Double, val height: Double)
12
-
13
- class WindowDimensionListener(private val context: ThemedReactContext?) {
11
+ data class Dimensions(
12
+ val width: Double,
13
+ val height: Double,
14
+ )
15
+
16
+ class WindowDimensionListener(
17
+ private val context: ThemedReactContext?,
18
+ ) {
14
19
  private var lastDispatchedDimensions = Dimensions(0.0, 0.0)
15
20
 
16
21
  init {
@@ -33,10 +38,11 @@ class WindowDimensionListener(private val context: ThemedReactContext?) {
33
38
  return
34
39
  }
35
40
 
36
- val newDimensions = Dimensions(
37
- content.width.toFloat().dp,
38
- content.height.toFloat().dp + content.marginTop.toFloat().dp,
39
- )
41
+ val newDimensions =
42
+ Dimensions(
43
+ content.width.toFloat().dp,
44
+ content.height.toFloat().dp + content.marginTop.toFloat().dp,
45
+ )
40
46
 
41
47
  if (newDimensions != lastDispatchedDimensions) {
42
48
  lastDispatchedDimensions = newDimensions
@@ -6,13 +6,21 @@ import com.reactnativekeyboardcontroller.BuildConfig
6
6
  object Logger {
7
7
  private val enabled = BuildConfig.DEBUG
8
8
 
9
- fun i(tag: String?, message: String, throwable: Throwable? = null) {
9
+ fun i(
10
+ tag: String?,
11
+ message: String,
12
+ throwable: Throwable? = null,
13
+ ) {
10
14
  if (enabled) {
11
15
  Log.i(tag, message, throwable)
12
16
  }
13
17
  }
14
18
 
15
- fun w(tag: String?, message: String, throwable: Throwable? = null) {
19
+ fun w(
20
+ tag: String?,
21
+ message: String,
22
+ throwable: Throwable? = null,
23
+ ) {
16
24
  if (enabled) {
17
25
  Log.w(tag, message, throwable)
18
26
  }