react-native-keyboard-controller 1.21.3 → 1.21.5
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.
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +2 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +10 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt +0 -40
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt +1 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +5 -1
- package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +10 -10
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +19 -22
- package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +2 -0
- package/ios/KeyboardControllerModule.mm +12 -0
- package/ios/observers/FocusedInputObserver.swift +9 -2
- package/ios/views/KeyboardExtenderContainerView.swift +14 -4
- package/lib/commonjs/bindings.js +4 -1
- package/lib/commonjs/bindings.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js +47 -10
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/types.js.map +1 -1
- package/lib/commonjs/components/KeyboardToolbar/constants.js +2 -2
- package/lib/commonjs/components/KeyboardToolbar/constants.js.map +1 -1
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/constants.js +3 -1
- package/lib/commonjs/constants.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/NativeKeyboardController.js.map +1 -1
- package/lib/commonjs/types/module.js.map +1 -1
- package/lib/module/bindings.js +4 -1
- package/lib/module/bindings.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/index.js +48 -11
- package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/types.js.map +1 -1
- package/lib/module/components/KeyboardToolbar/constants.js +2 -2
- package/lib/module/components/KeyboardToolbar/constants.js.map +1 -1
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/constants.js +3 -0
- package/lib/module/constants.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/NativeKeyboardController.js.map +1 -1
- package/lib/module/types/module.js.map +1 -1
- package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +1 -0
- package/lib/typescript/components/KeyboardAwareScrollView/types.d.ts +10 -0
- package/lib/typescript/components/index.d.ts +1 -1
- package/lib/typescript/constants.d.ts +1 -0
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/specs/NativeKeyboardController.d.ts +3 -1
- package/lib/typescript/types/module.d.ts +3 -0
- package/package.json +1 -1
- package/src/bindings.ts +3 -0
- package/src/components/KeyboardAwareScrollView/index.tsx +79 -29
- package/src/components/KeyboardAwareScrollView/types.ts +11 -0
- package/src/components/KeyboardToolbar/constants.ts +2 -3
- package/src/components/index.ts +1 -0
- package/src/constants.ts +4 -0
- package/src/index.ts +1 -0
- package/src/specs/NativeKeyboardController.ts +3 -1
- package/src/types/module.ts +4 -0
package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt
CHANGED
|
@@ -11,6 +11,8 @@ class KeyboardControllerModule(
|
|
|
11
11
|
|
|
12
12
|
override fun getName(): String = KeyboardControllerModuleImpl.NAME
|
|
13
13
|
|
|
14
|
+
override fun getTypedExportedConstants(): Map<String, Any> = module.getConstants()
|
|
15
|
+
|
|
14
16
|
override fun setInputMode(mode: Double) {
|
|
15
17
|
module.setInputMode(mode.toInt())
|
|
16
18
|
}
|
|
@@ -2,6 +2,7 @@ package com.reactnativekeyboardcontroller.extensions
|
|
|
2
2
|
|
|
3
3
|
import android.view.View
|
|
4
4
|
import android.view.ViewGroup
|
|
5
|
+
import android.view.WindowManager
|
|
5
6
|
import com.facebook.react.bridge.ReactContext
|
|
6
7
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
7
8
|
import com.facebook.react.uimanager.common.UIManagerType
|
|
@@ -28,3 +29,12 @@ val ReactContext.content: ViewGroup?
|
|
|
28
29
|
this.currentActivity?.window?.decorView?.rootView?.findViewById(
|
|
29
30
|
androidx.appcompat.R.id.action_bar_root,
|
|
30
31
|
)
|
|
32
|
+
|
|
33
|
+
val ReactContext.windowSoftInputMode: Int
|
|
34
|
+
get() =
|
|
35
|
+
this
|
|
36
|
+
.currentActivity
|
|
37
|
+
?.window
|
|
38
|
+
?.attributes
|
|
39
|
+
?.softInputMode
|
|
40
|
+
?: WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
|
|
@@ -4,9 +4,7 @@ import android.annotation.SuppressLint
|
|
|
4
4
|
import android.graphics.Rect
|
|
5
5
|
import android.os.Build
|
|
6
6
|
import android.view.View
|
|
7
|
-
import androidx.core.graphics.Insets
|
|
8
7
|
import androidx.core.view.ViewCompat
|
|
9
|
-
import androidx.core.view.WindowInsetsCompat
|
|
10
8
|
import com.reactnativekeyboardcontroller.log.Logger
|
|
11
9
|
|
|
12
10
|
/**
|
|
@@ -61,41 +59,3 @@ val View.screenLocation get(): IntArray {
|
|
|
61
59
|
|
|
62
60
|
return point
|
|
63
61
|
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Safely replaces status bar insets so that when we edge-to-edge mode gets disabled/enabled
|
|
67
|
-
* the app content is not jumping/resizing a window.
|
|
68
|
-
* */
|
|
69
|
-
@Suppress("DEPRECATION")
|
|
70
|
-
fun View.replaceStatusBarInsets(
|
|
71
|
-
insets: WindowInsetsCompat,
|
|
72
|
-
isStatusBarTranslucent: Boolean,
|
|
73
|
-
active: Boolean,
|
|
74
|
-
): WindowInsetsCompat {
|
|
75
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
76
|
-
val sysBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
|
77
|
-
val navBars = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
|
|
78
|
-
val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
|
|
79
|
-
val adjustedTop = if (isStatusBarTranslucent) 0 else sysBars.top
|
|
80
|
-
// pick bottom: use IME if present, otherwise nav bar bottom (respect translucency)
|
|
81
|
-
val bottomFromImeOrNav = if (ime.bottom > 0) ime.bottom else navBars.bottom
|
|
82
|
-
val adjustedInsets =
|
|
83
|
-
WindowInsetsCompat
|
|
84
|
-
.Builder(insets)
|
|
85
|
-
.setInsets(
|
|
86
|
-
WindowInsetsCompat.Type.systemBars(),
|
|
87
|
-
Insets.of(sysBars.left, adjustedTop, sysBars.right, if (active) sysBars.bottom else bottomFromImeOrNav),
|
|
88
|
-
).build()
|
|
89
|
-
|
|
90
|
-
return ViewCompat.onApplyWindowInsets(this, adjustedInsets)
|
|
91
|
-
} else {
|
|
92
|
-
val defaultInsets = ViewCompat.onApplyWindowInsets(this, insets)
|
|
93
|
-
|
|
94
|
-
return defaultInsets.replaceSystemWindowInsets(
|
|
95
|
-
defaultInsets.systemWindowInsetLeft,
|
|
96
|
-
if (isStatusBarTranslucent) 0 else defaultInsets.systemWindowInsetTop,
|
|
97
|
-
defaultInsets.systemWindowInsetRight,
|
|
98
|
-
defaultInsets.systemWindowInsetBottom,
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
@@ -13,11 +13,14 @@ import com.reactnativekeyboardcontroller.views.EdgeToEdgeReactViewGroup
|
|
|
13
13
|
|
|
14
14
|
class KeyboardControllerViewManagerImpl {
|
|
15
15
|
private var listener: WindowDimensionListener? = null
|
|
16
|
+
private var listenerContext: ThemedReactContext? = null
|
|
16
17
|
|
|
17
18
|
fun createViewInstance(reactContext: ThemedReactContext): EdgeToEdgeReactViewGroup {
|
|
18
|
-
if (listener == null) {
|
|
19
|
+
if (listener == null || listenerContext !== reactContext) {
|
|
20
|
+
listener?.detachListener()
|
|
19
21
|
listener = WindowDimensionListener(reactContext)
|
|
20
22
|
listener?.attachListener()
|
|
23
|
+
listenerContext = reactContext
|
|
21
24
|
}
|
|
22
25
|
return EdgeToEdgeReactViewGroup(reactContext)
|
|
23
26
|
}
|
|
@@ -25,6 +28,7 @@ class KeyboardControllerViewManagerImpl {
|
|
|
25
28
|
fun invalidate() {
|
|
26
29
|
listener?.detachListener()
|
|
27
30
|
listener = null
|
|
31
|
+
listenerContext = null
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
fun synchronizeFocusedInputLayout(view: EdgeToEdgeReactViewGroup) {
|
|
@@ -3,7 +3,6 @@ package com.reactnativekeyboardcontroller.modules
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.os.Build
|
|
5
5
|
import android.view.View
|
|
6
|
-
import android.view.WindowManager
|
|
7
6
|
import android.view.inputmethod.InputMethodManager
|
|
8
7
|
import com.facebook.react.bridge.Arguments
|
|
9
8
|
import com.facebook.react.bridge.Promise
|
|
@@ -12,6 +11,7 @@ import com.facebook.react.bridge.UiThreadUtil
|
|
|
12
11
|
import com.reactnativekeyboardcontroller.extensions.dp
|
|
13
12
|
import com.reactnativekeyboardcontroller.extensions.screenLocation
|
|
14
13
|
import com.reactnativekeyboardcontroller.extensions.uiManager
|
|
14
|
+
import com.reactnativekeyboardcontroller.extensions.windowSoftInputMode
|
|
15
15
|
import com.reactnativekeyboardcontroller.interactive.KeyboardAnimationController
|
|
16
16
|
import com.reactnativekeyboardcontroller.traversal.FocusedInputHolder
|
|
17
17
|
import com.reactnativekeyboardcontroller.traversal.ViewHierarchyNavigator
|
|
@@ -21,8 +21,9 @@ class KeyboardControllerModuleImpl(
|
|
|
21
21
|
) {
|
|
22
22
|
private val uiManager = mReactContext.uiManager
|
|
23
23
|
private val controller = KeyboardAnimationController()
|
|
24
|
-
private val mDefaultMode: Int =
|
|
24
|
+
private val mDefaultMode: Int = mReactContext.windowSoftInputMode
|
|
25
25
|
|
|
26
|
+
// region Module methods
|
|
26
27
|
fun setInputMode(mode: Int) {
|
|
27
28
|
setSoftInputMode(mode)
|
|
28
29
|
}
|
|
@@ -102,24 +103,23 @@ class KeyboardControllerModuleImpl(
|
|
|
102
103
|
promise.resolve(map)
|
|
103
104
|
}
|
|
104
105
|
}
|
|
106
|
+
// endregion
|
|
105
107
|
|
|
108
|
+
// region Helpers
|
|
106
109
|
private fun setSoftInputMode(mode: Int) {
|
|
107
110
|
UiThreadUtil.runOnUiThread {
|
|
108
|
-
if (
|
|
111
|
+
if (mReactContext.windowSoftInputMode != mode) {
|
|
109
112
|
mReactContext.currentActivity?.window?.setSoftInputMode(mode)
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
115
|
}
|
|
116
|
+
// endregion
|
|
113
117
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
.currentActivity
|
|
117
|
-
?.window
|
|
118
|
-
?.attributes
|
|
119
|
-
?.softInputMode
|
|
120
|
-
?: WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
|
|
118
|
+
// region Module constants
|
|
119
|
+
fun getConstants(): MutableMap<String, Any> = mutableMapOf("keyboardBorderRadius" to 0)
|
|
121
120
|
|
|
122
121
|
companion object {
|
|
123
122
|
const val NAME = "KeyboardController"
|
|
124
123
|
}
|
|
124
|
+
// endregion
|
|
125
125
|
}
|
package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt
CHANGED
|
@@ -5,6 +5,7 @@ import android.content.res.Configuration
|
|
|
5
5
|
import android.os.Handler
|
|
6
6
|
import android.os.Looper
|
|
7
7
|
import android.view.WindowManager
|
|
8
|
+
import android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|
|
8
9
|
import android.widget.FrameLayout
|
|
9
10
|
import androidx.core.view.ViewCompat
|
|
10
11
|
import androidx.core.view.WindowCompat
|
|
@@ -14,14 +15,15 @@ import com.facebook.react.uimanager.ThemedReactContext
|
|
|
14
15
|
import com.facebook.react.views.view.ReactViewGroup
|
|
15
16
|
import com.reactnativekeyboardcontroller.extensions.content
|
|
16
17
|
import com.reactnativekeyboardcontroller.extensions.removeSelf
|
|
17
|
-
import com.reactnativekeyboardcontroller.extensions.replaceStatusBarInsets
|
|
18
18
|
import com.reactnativekeyboardcontroller.extensions.requestApplyInsetsWhenAttached
|
|
19
19
|
import com.reactnativekeyboardcontroller.extensions.rootView
|
|
20
|
+
import com.reactnativekeyboardcontroller.extensions.windowSoftInputMode
|
|
20
21
|
import com.reactnativekeyboardcontroller.listeners.KeyboardAnimationCallback
|
|
21
22
|
import com.reactnativekeyboardcontroller.listeners.KeyboardAnimationCallbackConfig
|
|
22
23
|
import com.reactnativekeyboardcontroller.log.Logger
|
|
23
24
|
import com.reactnativekeyboardcontroller.modal.ModalAttachedWatcher
|
|
24
25
|
import java.lang.ref.WeakReference
|
|
26
|
+
import kotlin.math.max
|
|
25
27
|
|
|
26
28
|
private val TAG = EdgeToEdgeReactViewGroup::class.qualifiedName
|
|
27
29
|
|
|
@@ -44,7 +46,6 @@ class EdgeToEdgeReactViewGroup(
|
|
|
44
46
|
private var isStatusBarTranslucent = false
|
|
45
47
|
private var isNavigationBarTranslucent = false
|
|
46
48
|
private var isPreservingEdgeToEdge = false
|
|
47
|
-
private var isEdgeToEdge = false
|
|
48
49
|
var active: Boolean = false
|
|
49
50
|
set(value) {
|
|
50
51
|
field = value
|
|
@@ -110,47 +111,43 @@ class EdgeToEdgeReactViewGroup(
|
|
|
110
111
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
111
112
|
)
|
|
112
113
|
|
|
113
|
-
val
|
|
114
|
-
|
|
114
|
+
val shouldApplyBottomPadding =
|
|
115
|
+
!active && reactContext.windowSoftInputMode == SOFT_INPUT_ADJUST_RESIZE && !isPreservingEdgeToEdge
|
|
115
116
|
val navBarInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
|
|
116
117
|
val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
|
118
|
+
val keyboardInsets =
|
|
119
|
+
if (!shouldApplyBottomPadding) 0 else insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
|
|
117
120
|
|
|
118
121
|
params.setMargins(
|
|
119
122
|
navBarInsets.left,
|
|
120
|
-
if (
|
|
123
|
+
if (this.isStatusBarTranslucent) {
|
|
121
124
|
0
|
|
122
125
|
} else {
|
|
123
126
|
systemBarInsets.top
|
|
124
127
|
},
|
|
125
128
|
navBarInsets.right,
|
|
126
|
-
if (
|
|
127
|
-
|
|
129
|
+
if (this.isNavigationBarTranslucent) {
|
|
130
|
+
keyboardInsets
|
|
128
131
|
} else {
|
|
129
|
-
navBarInsets.bottom
|
|
132
|
+
max(navBarInsets.bottom, keyboardInsets)
|
|
130
133
|
},
|
|
131
134
|
)
|
|
132
135
|
content?.layoutParams = params
|
|
133
136
|
|
|
134
|
-
|
|
137
|
+
ViewCompat.onApplyWindowInsets(v, insets)
|
|
135
138
|
}
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
fun setEdgeToEdge() {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
reactContext.currentActivity?.let {
|
|
146
|
-
WindowCompat.setDecorFitsSystemWindows(
|
|
147
|
-
it.window,
|
|
148
|
-
!isEdgeToEdge,
|
|
149
|
-
)
|
|
150
|
-
}
|
|
151
|
-
// unclear legacy flag if it was set earlier
|
|
152
|
-
reactContext.currentActivity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
|
143
|
+
reactContext.currentActivity?.let {
|
|
144
|
+
WindowCompat.setDecorFitsSystemWindows(
|
|
145
|
+
it.window,
|
|
146
|
+
false,
|
|
147
|
+
)
|
|
153
148
|
}
|
|
149
|
+
// unclear legacy flag if it was set earlier
|
|
150
|
+
reactContext.currentActivity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
|
154
151
|
}
|
|
155
152
|
|
|
156
153
|
private fun setupKeyboardCallbacks() {
|
package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt
CHANGED
|
@@ -13,6 +13,8 @@ class KeyboardControllerModule(
|
|
|
13
13
|
|
|
14
14
|
override fun getName(): String = KeyboardControllerModuleImpl.NAME
|
|
15
15
|
|
|
16
|
+
override fun getConstants(): MutableMap<String, Any> = module.getConstants()
|
|
17
|
+
|
|
16
18
|
@ReactMethod
|
|
17
19
|
fun setInputMode(mode: Int) {
|
|
18
20
|
module.setInputMode(mode)
|
|
@@ -53,6 +53,18 @@ RCT_EXPORT_MODULE()
|
|
|
53
53
|
return NO;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
- (NSDictionary *)constantsToExport
|
|
57
|
+
{
|
|
58
|
+
return @{
|
|
59
|
+
@"keyboardBorderRadius" : @([KeyboardExtenderContainerView keyboardBorderRadius]),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
- (NSDictionary *)getConstants
|
|
64
|
+
{
|
|
65
|
+
return [self constantsToExport];
|
|
66
|
+
}
|
|
67
|
+
|
|
56
68
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
57
69
|
- (void)setDefaultMode
|
|
58
70
|
#else
|
|
@@ -112,9 +112,16 @@ public class FocusedInputObserver: NSObject {
|
|
|
112
112
|
NotificationCenter.default.removeObserver(self)
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
@objc func didReceiveFocus(_: Notification) {
|
|
115
|
+
@objc func didReceiveFocus(_ notification: Notification) {
|
|
116
116
|
if UIResponder.current == currentResponder {
|
|
117
|
-
//
|
|
117
|
+
// The same input is still focused — no need to re-run the full onFocus()
|
|
118
|
+
// setup (observers, delegate substitution, focusDidSet event). However,
|
|
119
|
+
// keyboardWillShowNotification also fires when the keyboard *resizes*
|
|
120
|
+
// (e.g. switching between text and emoji keyboards). In that case we must
|
|
121
|
+
// refresh the layout so consumers receive an up-to-date absoluteY.
|
|
122
|
+
if notification.name == UIResponder.keyboardWillShowNotification {
|
|
123
|
+
syncUpLayout()
|
|
124
|
+
}
|
|
118
125
|
return
|
|
119
126
|
}
|
|
120
127
|
|
|
@@ -9,16 +9,26 @@ import UIKit
|
|
|
9
9
|
|
|
10
10
|
@objc
|
|
11
11
|
public class KeyboardExtenderContainerView: NSObject {
|
|
12
|
-
|
|
12
|
+
private static func usesModernKeyboard() -> Bool {
|
|
13
13
|
#if canImport(UIKit.UIGlassEffect)
|
|
14
14
|
if #available(iOS 26.0, *) {
|
|
15
15
|
let requiresCompat = Bundle.main.object(forInfoDictionaryKey: "UIDesignRequiresCompatibility") as? Bool ?? false
|
|
16
|
-
|
|
17
|
-
return ModernContainerView(frame: frame, contentView: contentView)
|
|
18
|
-
}
|
|
16
|
+
return !requiresCompat
|
|
19
17
|
}
|
|
20
18
|
#endif
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@objc public static func keyboardBorderRadius() -> CGFloat {
|
|
23
|
+
return usesModernKeyboard() ? 30 : 0
|
|
24
|
+
}
|
|
21
25
|
|
|
26
|
+
@objc public static func create(frame: CGRect, contentView: UIView) -> UIView {
|
|
27
|
+
if usesModernKeyboard() {
|
|
28
|
+
if #available(iOS 26.0, *) {
|
|
29
|
+
return ModernContainerView(frame: frame, contentView: contentView)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
22
32
|
return LegacyContainerView(frame: frame, contentView: contentView)
|
|
23
33
|
}
|
|
24
34
|
}
|
package/lib/commonjs/bindings.js
CHANGED
|
@@ -19,7 +19,10 @@ const KeyboardControllerNative = exports.KeyboardControllerNative = {
|
|
|
19
19
|
height: 0
|
|
20
20
|
}),
|
|
21
21
|
addListener: NOOP,
|
|
22
|
-
removeListeners: NOOP
|
|
22
|
+
removeListeners: NOOP,
|
|
23
|
+
getConstants: () => ({
|
|
24
|
+
keyboardBorderRadius: 0
|
|
25
|
+
})
|
|
23
26
|
};
|
|
24
27
|
/**
|
|
25
28
|
* An event emitter that provides a way to subscribe to next keyboard events:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","NOOP","KeyboardControllerNative","exports","setDefaultMode","setInputMode","preload","dismiss","setFocusTo","viewPositionInWindow","Promise","resolve","x","y","width","height","addListener","removeListeners","KeyboardEvents","remove","FocusedInputEvents","WindowDimensionsEvents","KeyboardControllerView","View","KeyboardControllerViewCommands","synchronizeFocusedInputLayout","_ref","KeyboardGestureArea","RCTOverKeyboardView","KeyboardBackgroundView","RCTKeyboardExtender","ClippingScrollView","RCTKeyboardToolbarGroupView"],"sources":["bindings.ts"],"sourcesContent":["import { View } from \"react-native\";\n\nimport type {\n ClippingScrollViewProps,\n FocusedInputEventsModule,\n KeyboardBackgroundViewProps,\n KeyboardControllerNativeModule,\n KeyboardControllerProps,\n KeyboardEventsModule,\n KeyboardExtenderProps,\n KeyboardGestureAreaProps,\n KeyboardToolbarGroupViewProps,\n OverKeyboardViewProps,\n WindowDimensionsEventsModule,\n} from \"./types\";\nimport type { EmitterSubscription } from \"react-native\";\n\nconst NOOP = () => {};\n\nexport const KeyboardControllerNative: KeyboardControllerNativeModule = {\n setDefaultMode: NOOP,\n setInputMode: NOOP,\n preload: NOOP,\n dismiss: NOOP,\n setFocusTo: NOOP,\n viewPositionInWindow: () =>\n Promise.resolve({ x: 0, y: 0, width: 0, height: 0 }),\n addListener: NOOP,\n removeListeners: NOOP,\n};\n/**\n * An event emitter that provides a way to subscribe to next keyboard events:\n * - `keyboardWillShow`;\n * - `keyboardDidShow`;\n * - `keyboardWillHide`;\n * - `keyboardDidHide`.\n *\n * Use `addListener` function to add your event listener for a specific keyboard event.\n */\nexport const KeyboardEvents: KeyboardEventsModule = {\n addListener: () => ({ remove: NOOP } as EmitterSubscription),\n};\n/**\n * This API is not documented, it's for internal usage only (for now), and is a subject to potential breaking changes in future.\n * Use it with cautious.\n */\nexport const FocusedInputEvents: FocusedInputEventsModule = {\n addListener: () => ({ remove: NOOP } as EmitterSubscription),\n};\nexport const WindowDimensionsEvents: WindowDimensionsEventsModule = {\n addListener: () => ({ remove: NOOP } as EmitterSubscription),\n};\n/**\n * A view that sends events whenever keyboard or focused events are happening.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller-view|Documentation} page for more details.\n */\nexport const KeyboardControllerView =\n View as unknown as React.FC<KeyboardControllerProps>;\nexport const KeyboardControllerViewCommands = {\n synchronizeFocusedInputLayout: (\n _ref: React.Component<KeyboardControllerProps> | null,\n ) => {},\n};\n/**\n * A view that defines a region on the screen, where gestures will control the keyboard position.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-gesture-area|Documentation} page for more details.\n */\nexport const KeyboardGestureArea =\n View as unknown as React.FC<KeyboardGestureAreaProps>;\nexport const RCTOverKeyboardView =\n View as unknown as React.FC<OverKeyboardViewProps>;\n/**\n * A view that matches keyboard background.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-background-view|Documentation} page for more details.\n */\nexport const KeyboardBackgroundView =\n View as unknown as React.FC<KeyboardBackgroundViewProps>;\n/**\n * A container that will embed its children into the keyboard\n * and will always show them above the keyboard.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-extender|Documentation} page for more details.\n */\nexport const RCTKeyboardExtender =\n View as unknown as React.FC<KeyboardExtenderProps>;\n/**\n * A decorator that will clip the content of the `ScrollView`. It helps to simulate `contentInset` behavior on Android\n * Supports only `bottom` property (`paddingBottom` is not supported property of `ScrollView.style`).\n * Using this component we can modify bottom inset without having a fake view.\n *\n * On iOS we use swizzling to apply runtime patches to fix some broken internal methods.\n * Ideally this component shouldn't exist and all its fixes/polyfills must be added directly to react-native and\n * we will port features/fixes back to upstream, but at the moment we use this view to\n * deliver desired functionality regardless of react-native version used.\n */\nexport const ClippingScrollView =\n View as unknown as React.FC<ClippingScrollViewProps>;\n/**\n * A View that defines a group of `TextInput`s.\n * Used in toolbar navigation to assure that you can navigate only between inputs withing the same group.\n */\nexport const RCTKeyboardToolbarGroupView =\n View as unknown as React.FC<KeyboardToolbarGroupViewProps>;\n"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAiBA,MAAMC,IAAI,GAAGA,CAAA,KAAM,CAAC,CAAC;AAEd,MAAMC,wBAAwD,GAAAC,OAAA,CAAAD,wBAAA,GAAG;EACtEE,cAAc,EAAEH,IAAI;EACpBI,YAAY,EAAEJ,IAAI;EAClBK,OAAO,EAAEL,IAAI;EACbM,OAAO,EAAEN,IAAI;EACbO,UAAU,EAAEP,IAAI;EAChBQ,oBAAoB,EAAEA,CAAA,KACpBC,OAAO,CAACC,OAAO,CAAC;IAAEC,CAAC,EAAE,CAAC;IAAEC,CAAC,EAAE,CAAC;IAAEC,KAAK,EAAE,CAAC;IAAEC,MAAM,EAAE;EAAE,CAAC,CAAC;EACtDC,WAAW,EAAEf,IAAI;EACjBgB,eAAe,EAAEhB;
|
|
1
|
+
{"version":3,"names":["_reactNative","require","NOOP","KeyboardControllerNative","exports","setDefaultMode","setInputMode","preload","dismiss","setFocusTo","viewPositionInWindow","Promise","resolve","x","y","width","height","addListener","removeListeners","getConstants","keyboardBorderRadius","KeyboardEvents","remove","FocusedInputEvents","WindowDimensionsEvents","KeyboardControllerView","View","KeyboardControllerViewCommands","synchronizeFocusedInputLayout","_ref","KeyboardGestureArea","RCTOverKeyboardView","KeyboardBackgroundView","RCTKeyboardExtender","ClippingScrollView","RCTKeyboardToolbarGroupView"],"sources":["bindings.ts"],"sourcesContent":["import { View } from \"react-native\";\n\nimport type {\n ClippingScrollViewProps,\n FocusedInputEventsModule,\n KeyboardBackgroundViewProps,\n KeyboardControllerNativeModule,\n KeyboardControllerProps,\n KeyboardEventsModule,\n KeyboardExtenderProps,\n KeyboardGestureAreaProps,\n KeyboardToolbarGroupViewProps,\n OverKeyboardViewProps,\n WindowDimensionsEventsModule,\n} from \"./types\";\nimport type { EmitterSubscription } from \"react-native\";\n\nconst NOOP = () => {};\n\nexport const KeyboardControllerNative: KeyboardControllerNativeModule = {\n setDefaultMode: NOOP,\n setInputMode: NOOP,\n preload: NOOP,\n dismiss: NOOP,\n setFocusTo: NOOP,\n viewPositionInWindow: () =>\n Promise.resolve({ x: 0, y: 0, width: 0, height: 0 }),\n addListener: NOOP,\n removeListeners: NOOP,\n getConstants: () => ({\n keyboardBorderRadius: 0,\n }),\n};\n/**\n * An event emitter that provides a way to subscribe to next keyboard events:\n * - `keyboardWillShow`;\n * - `keyboardDidShow`;\n * - `keyboardWillHide`;\n * - `keyboardDidHide`.\n *\n * Use `addListener` function to add your event listener for a specific keyboard event.\n */\nexport const KeyboardEvents: KeyboardEventsModule = {\n addListener: () => ({ remove: NOOP } as EmitterSubscription),\n};\n/**\n * This API is not documented, it's for internal usage only (for now), and is a subject to potential breaking changes in future.\n * Use it with cautious.\n */\nexport const FocusedInputEvents: FocusedInputEventsModule = {\n addListener: () => ({ remove: NOOP } as EmitterSubscription),\n};\nexport const WindowDimensionsEvents: WindowDimensionsEventsModule = {\n addListener: () => ({ remove: NOOP } as EmitterSubscription),\n};\n/**\n * A view that sends events whenever keyboard or focused events are happening.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller-view|Documentation} page for more details.\n */\nexport const KeyboardControllerView =\n View as unknown as React.FC<KeyboardControllerProps>;\nexport const KeyboardControllerViewCommands = {\n synchronizeFocusedInputLayout: (\n _ref: React.Component<KeyboardControllerProps> | null,\n ) => {},\n};\n/**\n * A view that defines a region on the screen, where gestures will control the keyboard position.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-gesture-area|Documentation} page for more details.\n */\nexport const KeyboardGestureArea =\n View as unknown as React.FC<KeyboardGestureAreaProps>;\nexport const RCTOverKeyboardView =\n View as unknown as React.FC<OverKeyboardViewProps>;\n/**\n * A view that matches keyboard background.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-background-view|Documentation} page for more details.\n */\nexport const KeyboardBackgroundView =\n View as unknown as React.FC<KeyboardBackgroundViewProps>;\n/**\n * A container that will embed its children into the keyboard\n * and will always show them above the keyboard.\n *\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-extender|Documentation} page for more details.\n */\nexport const RCTKeyboardExtender =\n View as unknown as React.FC<KeyboardExtenderProps>;\n/**\n * A decorator that will clip the content of the `ScrollView`. It helps to simulate `contentInset` behavior on Android\n * Supports only `bottom` property (`paddingBottom` is not supported property of `ScrollView.style`).\n * Using this component we can modify bottom inset without having a fake view.\n *\n * On iOS we use swizzling to apply runtime patches to fix some broken internal methods.\n * Ideally this component shouldn't exist and all its fixes/polyfills must be added directly to react-native and\n * we will port features/fixes back to upstream, but at the moment we use this view to\n * deliver desired functionality regardless of react-native version used.\n */\nexport const ClippingScrollView =\n View as unknown as React.FC<ClippingScrollViewProps>;\n/**\n * A View that defines a group of `TextInput`s.\n * Used in toolbar navigation to assure that you can navigate only between inputs withing the same group.\n */\nexport const RCTKeyboardToolbarGroupView =\n View as unknown as React.FC<KeyboardToolbarGroupViewProps>;\n"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAiBA,MAAMC,IAAI,GAAGA,CAAA,KAAM,CAAC,CAAC;AAEd,MAAMC,wBAAwD,GAAAC,OAAA,CAAAD,wBAAA,GAAG;EACtEE,cAAc,EAAEH,IAAI;EACpBI,YAAY,EAAEJ,IAAI;EAClBK,OAAO,EAAEL,IAAI;EACbM,OAAO,EAAEN,IAAI;EACbO,UAAU,EAAEP,IAAI;EAChBQ,oBAAoB,EAAEA,CAAA,KACpBC,OAAO,CAACC,OAAO,CAAC;IAAEC,CAAC,EAAE,CAAC;IAAEC,CAAC,EAAE,CAAC;IAAEC,KAAK,EAAE,CAAC;IAAEC,MAAM,EAAE;EAAE,CAAC,CAAC;EACtDC,WAAW,EAAEf,IAAI;EACjBgB,eAAe,EAAEhB,IAAI;EACrBiB,YAAY,EAAEA,CAAA,MAAO;IACnBC,oBAAoB,EAAE;EACxB,CAAC;AACH,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,cAAoC,GAAAjB,OAAA,CAAAiB,cAAA,GAAG;EAClDJ,WAAW,EAAEA,CAAA,MAAO;IAAEK,MAAM,EAAEpB;EAAK,CAAC;AACtC,CAAC;AACD;AACA;AACA;AACA;AACO,MAAMqB,kBAA4C,GAAAnB,OAAA,CAAAmB,kBAAA,GAAG;EAC1DN,WAAW,EAAEA,CAAA,MAAO;IAAEK,MAAM,EAAEpB;EAAK,CAAC;AACtC,CAAC;AACM,MAAMsB,sBAAoD,GAAApB,OAAA,CAAAoB,sBAAA,GAAG;EAClEP,WAAW,EAAEA,CAAA,MAAO;IAAEK,MAAM,EAAEpB;EAAK,CAAC;AACtC,CAAC;AACD;AACA;AACA;AACA;AACA;AACO,MAAMuB,sBAAsB,GAAArB,OAAA,CAAAqB,sBAAA,GACjCC,iBAAoD;AAC/C,MAAMC,8BAA8B,GAAAvB,OAAA,CAAAuB,8BAAA,GAAG;EAC5CC,6BAA6B,EAC3BC,IAAqD,IAClD,CAAC;AACR,CAAC;AACD;AACA;AACA;AACA;AACA;AACO,MAAMC,mBAAmB,GAAA1B,OAAA,CAAA0B,mBAAA,GAC9BJ,iBAAqD;AAChD,MAAMK,mBAAmB,GAAA3B,OAAA,CAAA2B,mBAAA,GAC9BL,iBAAkD;AACpD;AACA;AACA;AACA;AACA;AACO,MAAMM,sBAAsB,GAAA5B,OAAA,CAAA4B,sBAAA,GACjCN,iBAAwD;AAC1D;AACA;AACA;AACA;AACA;AACA;AACO,MAAMO,mBAAmB,GAAA7B,OAAA,CAAA6B,mBAAA,GAC9BP,iBAAkD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMQ,kBAAkB,GAAA9B,OAAA,CAAA8B,kBAAA,GAC7BR,iBAAoD;AACtD;AACA;AACA;AACA;AACO,MAAMS,2BAA2B,GAAA/B,OAAA,CAAA+B,2BAAA,GACtCT,iBAA0D","ignoreList":[]}
|
|
@@ -77,6 +77,7 @@ const KeyboardAwareScrollView = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
77
77
|
disableScrollOnKeyboardHide = false,
|
|
78
78
|
enabled = true,
|
|
79
79
|
extraKeyboardSpace = 0,
|
|
80
|
+
mode = "insets",
|
|
80
81
|
ScrollViewComponent = _reactNativeReanimated.default.ScrollView,
|
|
81
82
|
snapToOffsets,
|
|
82
83
|
...rest
|
|
@@ -162,15 +163,21 @@ const KeyboardAwareScrollView = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
162
163
|
const removeGhostPadding = (0, _react.useCallback)(e => {
|
|
163
164
|
"worklet";
|
|
164
165
|
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
|
|
166
|
+
// layout mode: the spacer view participates in layout, so the ScrollView
|
|
167
|
+
// reflows naturally when it shrinks — no manual scroll correction needed.
|
|
168
|
+
if (mode === "layout") {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// insets mode: `ScrollViewWithBottomPadding` extends scrollable area without
|
|
173
|
+
// changing layout, so when the keyboard hides and we're at the end of the
|
|
174
|
+
// ScrollView we must manually scroll back.
|
|
168
175
|
if (!keyboardWillAppear.value && ghostViewSpace.value > 0) {
|
|
169
176
|
(0, _reactNativeReanimated.scrollTo)(scrollViewAnimatedRef, 0, scrollPosition.value - (0, _reactNativeReanimated.interpolate)(e, [initialKeyboardSize.value, keyboardHeight.value], [ghostViewSpace.value, 0]), false);
|
|
170
177
|
return true;
|
|
171
178
|
}
|
|
172
179
|
return false;
|
|
173
|
-
}, []);
|
|
180
|
+
}, [mode]);
|
|
174
181
|
const performScrollWithPositionRestoration = (0, _react.useCallback)(newPosition => {
|
|
175
182
|
"worklet";
|
|
176
183
|
|
|
@@ -280,8 +287,14 @@ const KeyboardAwareScrollView = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
280
287
|
scrollPosition.value = position.value;
|
|
281
288
|
// just persist height - later will be used in interpolation
|
|
282
289
|
keyboardHeight.value = e.height;
|
|
283
|
-
|
|
284
|
-
|
|
290
|
+
|
|
291
|
+
// insets mode: set the full contentInset upfront so that maybeScroll
|
|
292
|
+
// calculations are correct from the very first onMove frame.
|
|
293
|
+
// layout mode: do NOT set it here — the spacer must grow frame-by-frame
|
|
294
|
+
// in onMove to avoid a premature full-height jump before the keyboard moves.
|
|
295
|
+
if (mode === "insets") {
|
|
296
|
+
syncKeyboardFrame(e);
|
|
297
|
+
}
|
|
285
298
|
}
|
|
286
299
|
|
|
287
300
|
// focus was changed
|
|
@@ -318,9 +331,11 @@ const KeyboardAwareScrollView = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
318
331
|
position.value += maybeScroll(e.height, true);
|
|
319
332
|
}
|
|
320
333
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
334
|
+
if (mode === "insets") {
|
|
335
|
+
ghostViewSpace.value = position.value + scrollViewLayout.value.height - scrollViewContentSize.value.height;
|
|
336
|
+
if (ghostViewSpace.value > 0) {
|
|
337
|
+
scrollPosition.value = position.value;
|
|
338
|
+
}
|
|
324
339
|
}
|
|
325
340
|
},
|
|
326
341
|
onMove: e => {
|
|
@@ -330,6 +345,11 @@ const KeyboardAwareScrollView = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
330
345
|
return;
|
|
331
346
|
}
|
|
332
347
|
|
|
348
|
+
// layout mode: drive the spacer view animation frame-by-frame
|
|
349
|
+
if (mode === "layout") {
|
|
350
|
+
syncKeyboardFrame(e);
|
|
351
|
+
}
|
|
352
|
+
|
|
333
353
|
// if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens
|
|
334
354
|
if (!disableScrollOnKeyboardHide || keyboardWillAppear.value) {
|
|
335
355
|
maybeScroll(e.height);
|
|
@@ -353,7 +373,7 @@ const KeyboardAwareScrollView = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
353
373
|
}
|
|
354
374
|
syncKeyboardFrame(e);
|
|
355
375
|
}
|
|
356
|
-
}, [maybeScroll, removeGhostPadding, disableScrollOnKeyboardHide, syncKeyboardFrame]);
|
|
376
|
+
}, [mode, maybeScroll, removeGhostPadding, disableScrollOnKeyboardHide, syncKeyboardFrame]);
|
|
357
377
|
const synchronize = (0, _react.useCallback)(async () => {
|
|
358
378
|
await update();
|
|
359
379
|
(0, _reactNativeReanimated.runOnUI)(() => {
|
|
@@ -389,6 +409,23 @@ const KeyboardAwareScrollView = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
389
409
|
}
|
|
390
410
|
}, []);
|
|
391
411
|
const padding = (0, _reactNativeReanimated.useDerivedValue)(() => enabled ? currentKeyboardFrameHeight.value : 0, [enabled]);
|
|
412
|
+
// layout mode only: a spacer view whose paddingBottom grows with the keyboard.
|
|
413
|
+
// The `+ 1` ensures the scroll view never reaches its absolute end during animation,
|
|
414
|
+
// avoiding the layout recalculation that triggers on every frame at the boundary.
|
|
415
|
+
// see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342
|
|
416
|
+
const layoutSpacerStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => enabled && mode === "layout" ? {
|
|
417
|
+
paddingBottom: currentKeyboardFrameHeight.value + 1
|
|
418
|
+
} : {}, [enabled, mode]);
|
|
419
|
+
if (mode === "layout") {
|
|
420
|
+
return /*#__PURE__*/_react.default.createElement(ScrollViewComponent, _extends({
|
|
421
|
+
ref: onRef
|
|
422
|
+
}, rest, {
|
|
423
|
+
scrollEventThrottle: 16,
|
|
424
|
+
onLayout: onScrollViewLayout
|
|
425
|
+
}), children, enabled && /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
|
|
426
|
+
style: layoutSpacerStyle
|
|
427
|
+
}));
|
|
428
|
+
}
|
|
392
429
|
return /*#__PURE__*/_react.default.createElement(_ScrollViewWithBottomPadding.default, _extends({
|
|
393
430
|
ref: onRef
|
|
394
431
|
}, rest, {
|