react-native-keyboard-controller 1.21.7 → 1.21.8

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.
@@ -31,6 +31,13 @@ import kotlin.math.abs
31
31
  private val TAG = KeyboardAnimationCallback::class.qualifiedName
32
32
  private val isResizeHandledInCallbackMethods = Keyboard.IS_ANIMATION_EMULATED
33
33
 
34
+ private data class PendingKeyboardStartEvent(
35
+ val keyboardHeight: Double,
36
+ val progress: Double,
37
+ val duration: Int,
38
+ val target: Int,
39
+ )
40
+
34
41
  data class KeyboardAnimationCallbackConfig(
35
42
  val persistentInsetTypes: Int,
36
43
  val deferredInsetTypes: Int,
@@ -63,6 +70,7 @@ class KeyboardAnimationCallback(
63
70
  private var isTransitioning = false
64
71
  private var duration = 0
65
72
  private var viewTagFocused = -1
73
+ private var pendingStartEvent: PendingKeyboardStartEvent? = null
66
74
  private var animationsToSkip = hashSetOf<WindowInsetsAnimationCompat>()
67
75
  private val isKeyboardInteractive: Boolean
68
76
  get() = duration == -1
@@ -177,6 +185,7 @@ class KeyboardAnimationCallback(
177
185
  }
178
186
 
179
187
  isTransitioning = true
188
+ pendingStartEvent = null
180
189
  isKeyboardVisible = isKeyboardVisible()
181
190
  duration = animation.durationMillis.toInt()
182
191
  val keyboardHeight = getCurrentKeyboardHeight()
@@ -205,18 +214,16 @@ class KeyboardAnimationCallback(
205
214
  )
206
215
 
207
216
  Logger.i(TAG, "HEIGHT:: $keyboardHeight TAG:: $viewTagFocused")
208
- context.dispatchEvent(
209
- eventPropagationView.id,
210
- KeyboardTransitionEvent(
211
- surfaceId,
212
- eventPropagationView.id,
213
- KeyboardTransitionEvent.Start,
217
+ // AOSP calls app onStart before its internal listener.onReady. Dispatching
218
+ // a RN event here lets Reanimated synchronously mutate Fabric and can
219
+ // cancel the pending IME controller before Android starts its animator.
220
+ pendingStartEvent =
221
+ PendingKeyboardStartEvent(
214
222
  keyboardHeight,
215
223
  if (!isKeyboardVisible) 0.0 else 1.0,
216
224
  duration,
217
225
  viewTagFocused,
218
- ),
219
- )
226
+ )
220
227
 
221
228
  return super.onStart(animation, bounds)
222
229
  }
@@ -265,24 +272,27 @@ class KeyboardAnimationCallback(
265
272
  "DiffY: $diffY $height $progress ${InteractiveKeyboardProvider.isInteractive} $viewTagFocused",
266
273
  )
267
274
 
268
- val event =
269
- if (InteractiveKeyboardProvider.isInteractive) {
270
- KeyboardTransitionEvent.Interactive
271
- } else {
272
- KeyboardTransitionEvent.Move
273
- }
274
- context.dispatchEvent(
275
- eventPropagationView.id,
276
- KeyboardTransitionEvent(
277
- surfaceId,
275
+ flushPendingStartEvent()
276
+ if (isTransitioning) {
277
+ val event =
278
+ if (InteractiveKeyboardProvider.isInteractive) {
279
+ KeyboardTransitionEvent.Interactive
280
+ } else {
281
+ KeyboardTransitionEvent.Move
282
+ }
283
+ context.dispatchEvent(
278
284
  eventPropagationView.id,
279
- event,
280
- height,
281
- progress,
282
- duration,
283
- viewTagFocused,
284
- ),
285
- )
285
+ KeyboardTransitionEvent(
286
+ surfaceId,
287
+ eventPropagationView.id,
288
+ event,
289
+ height,
290
+ progress,
291
+ duration,
292
+ viewTagFocused,
293
+ ),
294
+ )
295
+ }
286
296
 
287
297
  return insets
288
298
  }
@@ -306,10 +316,13 @@ class KeyboardAnimationCallback(
306
316
 
307
317
  if (animation in animationsToSkip) {
308
318
  duration = 0
319
+ pendingStartEvent = null
309
320
  animationsToSkip.remove(animation)
310
321
  return@Runnable
311
322
  }
312
323
 
324
+ flushPendingStartEvent()
325
+
313
326
  context.emitEvent(
314
327
  "KeyboardController::" + if (!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow",
315
328
  getEventParams(keyboardHeight),
@@ -352,6 +365,7 @@ class KeyboardAnimationCallback(
352
365
  prevKeyboardHeight = keyboardHeight
353
366
  isTransitioning = false
354
367
  duration = 0
368
+ pendingStartEvent = null
355
369
 
356
370
  context.emitEvent(
357
371
  "KeyboardController::" + if (!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow",
@@ -375,6 +389,7 @@ class KeyboardAnimationCallback(
375
389
  }
376
390
 
377
391
  fun destroy() {
392
+ pendingStartEvent = null
378
393
  view.viewTreeObserver.removeOnGlobalFocusChangeListener(focusListener)
379
394
  layoutObserver?.destroy()
380
395
  }
@@ -430,6 +445,24 @@ class KeyboardAnimationCallback(
430
445
  return (keyboardHeight - navigationBar).toFloat().dp.coerceAtLeast(0.0)
431
446
  }
432
447
 
448
+ private fun flushPendingStartEvent() {
449
+ val event = pendingStartEvent ?: return
450
+
451
+ pendingStartEvent = null
452
+ context.dispatchEvent(
453
+ eventPropagationView.id,
454
+ KeyboardTransitionEvent(
455
+ surfaceId,
456
+ eventPropagationView.id,
457
+ KeyboardTransitionEvent.Start,
458
+ event.keyboardHeight,
459
+ event.progress,
460
+ event.duration,
461
+ event.target,
462
+ ),
463
+ )
464
+ }
465
+
433
466
  private fun getEventParams(height: Double): WritableMap {
434
467
  val params: WritableMap = Arguments.createMap()
435
468
  params.putDouble("height", height)
@@ -7,7 +7,7 @@
7
7
 
8
8
  final class KeyboardViewLocator {
9
9
  static let shared = KeyboardViewLocator()
10
- private var cachedKeyboardView: UIView?
10
+ private weak var cachedKeyboardView: UIView?
11
11
  private var cachedWindowsCount: Int = 0
12
12
 
13
13
  func resolve() -> UIView? {
@@ -16,6 +16,7 @@
16
16
  #import "RCTFabricComponentsPlugins.h"
17
17
  #endif
18
18
 
19
+ #import <TargetConditionals.h>
19
20
  #import <UIKit/UIKit.h>
20
21
  #import <objc/runtime.h>
21
22
 
@@ -213,11 +214,16 @@ RCT_EXPORT_VIEW_PROPERTY(applyWorkaroundForContentInsetHitTestBug, BOOL)
213
214
  {
214
215
  [super didMoveToWindow];
215
216
  if (self.window) {
217
+ #if TARGET_OS_MACCATALYST
218
+ // Catalyst UIScrollView is AppKit-backed; avoid runtime subclassing it.
219
+ return;
220
+ #else
216
221
  UIScrollView *scrollView = KCFindFirstScrollView(self);
217
222
  KCApplyNoopScrollRectToVisible(scrollView);
218
223
  if (self.applyWorkaroundForContentInsetHitTestBug) {
219
224
  KCApplyFixedHitTest(scrollView);
220
225
  }
226
+ #endif
221
227
  }
222
228
  }
223
229
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-keyboard-controller",
3
- "version": "1.21.7",
3
+ "version": "1.21.8",
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",