react-native-keyboard-controller 1.12.6 → 1.13.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.
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +5 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +13 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt +0 -10
- package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/Interpolator.kt +2 -1
- package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/IosInterpolator.kt +2 -1
- package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/LinearInterpolator.kt +1 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt +15 -8
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +71 -59
- package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardGestureAreaViewManagerImpl.kt +4 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt +80 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/modules/StatusBarManagerCompatModuleImpl.kt +6 -12
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +31 -4
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardGestureAreaReactViewGroup.kt +7 -0
- package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +5 -0
- package/ios/core/KeyboardAnimation.swift +1 -1
- package/ios/core/TimingAnimation.swift +108 -0
- package/ios/extensions/UIApplication.swift +29 -0
- package/ios/extensions/UIView.swift +10 -0
- package/ios/observers/FocusedInputObserver.swift +2 -0
- package/ios/observers/KeyboardMovementObserver.swift +19 -10
- package/ios/traversal/ViewHierarchyNavigator.swift +1 -1
- package/ios/views/KeyboardControllerView.mm +30 -39
- package/lib/commonjs/animated.js +16 -30
- package/lib/commonjs/animated.js.map +1 -1
- package/lib/commonjs/bindings.js.map +1 -1
- package/lib/commonjs/bindings.native.js.map +1 -1
- package/lib/commonjs/components/KeyboardAvoidingView/hooks.js +3 -14
- package/lib/commonjs/components/KeyboardAvoidingView/hooks.js.map +1 -1
- package/lib/commonjs/components/KeyboardAvoidingView/index.js +5 -4
- package/lib/commonjs/components/KeyboardAvoidingView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js +42 -16
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js +1 -0
- package/lib/commonjs/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/utils.js.map +1 -1
- package/lib/commonjs/components/KeyboardStickyView/index.js +2 -2
- package/lib/commonjs/components/KeyboardStickyView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardToolbar/Arrow.js +2 -2
- package/lib/commonjs/components/KeyboardToolbar/Arrow.js.map +1 -1
- package/lib/commonjs/components/KeyboardToolbar/Button.js +12 -12
- package/lib/commonjs/components/KeyboardToolbar/Button.js.map +1 -1
- package/lib/commonjs/components/KeyboardToolbar/index.js +33 -27
- package/lib/commonjs/components/KeyboardToolbar/index.js.map +1 -1
- package/lib/commonjs/components/index.js +2 -2
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/context.js +3 -2
- package/lib/commonjs/context.js.map +1 -1
- package/lib/commonjs/event-handler.js +19 -0
- package/lib/commonjs/event-handler.js.map +1 -0
- package/lib/commonjs/event-handler.web.js +10 -0
- package/lib/commonjs/event-handler.web.js.map +1 -0
- package/lib/commonjs/event-mappings.js +9 -0
- package/lib/commonjs/event-mappings.js.map +1 -0
- package/lib/commonjs/hooks/index.js +8 -21
- package/lib/commonjs/hooks/index.js.map +1 -1
- package/lib/commonjs/hooks/useSyncEffect/index.js +37 -0
- package/lib/commonjs/hooks/useSyncEffect/index.js.map +1 -0
- package/lib/commonjs/internal.js +20 -43
- package/lib/commonjs/internal.js.map +1 -1
- package/lib/commonjs/monkey-patch.android.js +1 -1
- package/lib/commonjs/monkey-patch.android.js.map +1 -1
- package/lib/commonjs/monkey-patch.js.map +1 -1
- package/lib/commonjs/reanimated.js +1 -3
- package/lib/commonjs/reanimated.js.map +1 -1
- package/lib/commonjs/reanimated.native.js +1 -35
- package/lib/commonjs/reanimated.native.js.map +1 -1
- package/lib/commonjs/specs/KeyboardControllerViewNativeComponent.js +1 -1
- package/lib/commonjs/specs/KeyboardControllerViewNativeComponent.js.map +1 -1
- package/lib/commonjs/specs/KeyboardGestureAreaNativeComponent.js +1 -1
- package/lib/commonjs/specs/KeyboardGestureAreaNativeComponent.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/module/animated.js +17 -32
- package/lib/module/animated.js.map +1 -1
- package/lib/module/bindings.js.map +1 -1
- package/lib/module/bindings.native.js.map +1 -1
- package/lib/module/components/KeyboardAvoidingView/hooks.js +3 -14
- package/lib/module/components/KeyboardAvoidingView/hooks.js.map +1 -1
- package/lib/module/components/KeyboardAvoidingView/index.js +4 -3
- package/lib/module/components/KeyboardAvoidingView/index.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/index.js +41 -15
- package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js +1 -0
- package/lib/module/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/utils.js.map +1 -1
- package/lib/module/components/KeyboardStickyView/index.js +1 -1
- package/lib/module/components/KeyboardToolbar/Button.js +10 -10
- package/lib/module/components/KeyboardToolbar/Button.js.map +1 -1
- package/lib/module/components/KeyboardToolbar/index.js +31 -25
- package/lib/module/components/KeyboardToolbar/index.js.map +1 -1
- package/lib/module/context.js +3 -2
- package/lib/module/context.js.map +1 -1
- package/lib/module/event-handler.js +13 -0
- package/lib/module/event-handler.js.map +1 -0
- package/lib/module/event-handler.web.js +5 -0
- package/lib/module/event-handler.web.js.map +1 -0
- package/lib/module/event-mappings.js +3 -0
- package/lib/module/event-mappings.js.map +1 -0
- package/lib/module/hooks/index.js +7 -21
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/hooks/useSyncEffect/index.js +31 -0
- package/lib/module/hooks/useSyncEffect/index.js.map +1 -0
- package/lib/module/internal.js +21 -44
- package/lib/module/internal.js.map +1 -1
- package/lib/module/monkey-patch.js.map +1 -1
- package/lib/module/reanimated.js +0 -2
- package/lib/module/reanimated.js.map +1 -1
- package/lib/module/reanimated.native.js +0 -32
- package/lib/module/reanimated.native.js.map +1 -1
- package/lib/module/specs/KeyboardGestureAreaNativeComponent.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/components/KeyboardToolbar/Button.d.ts +2 -2
- package/lib/typescript/components/KeyboardToolbar/index.d.ts +4 -3
- package/lib/typescript/context.d.ts +3 -3
- package/lib/typescript/event-handler.d.ts +3 -0
- package/lib/typescript/event-mappings.d.ts +2 -0
- package/lib/typescript/hooks/index.d.ts +1 -1
- package/lib/typescript/hooks/useSyncEffect/index.d.ts +14 -0
- package/lib/typescript/internal.d.ts +5 -19
- package/lib/typescript/reanimated.d.ts +1 -3
- package/lib/typescript/reanimated.native.d.ts +1 -3
- package/lib/typescript/specs/KeyboardGestureAreaNativeComponent.d.ts +2 -1
- package/lib/typescript/types.d.ts +6 -0
- package/package.json +14 -7
- package/src/animated.tsx +21 -43
- package/src/bindings.native.ts +1 -0
- package/src/bindings.ts +1 -0
- package/src/components/KeyboardAvoidingView/hooks.ts +3 -13
- package/src/components/KeyboardAvoidingView/index.tsx +2 -1
- package/src/components/KeyboardAwareScrollView/index.tsx +51 -13
- package/src/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.ts +2 -0
- package/src/components/KeyboardAwareScrollView/utils.ts +1 -0
- package/src/components/KeyboardToolbar/Button.tsx +11 -11
- package/src/components/KeyboardToolbar/index.tsx +45 -25
- package/src/context.ts +8 -6
- package/src/event-handler.js +15 -0
- package/src/event-handler.ts +8 -0
- package/src/event-handler.web.js +5 -0
- package/src/event-mappings.ts +14 -0
- package/src/hooks/index.ts +9 -16
- package/src/hooks/useSyncEffect/index.ts +36 -0
- package/src/internal.ts +34 -53
- package/src/monkey-patch.ts +1 -0
- package/src/reanimated.native.ts +0 -50
- package/src/reanimated.ts +1 -12
- package/src/specs/KeyboardGestureAreaNativeComponent.ts +5 -1
- package/src/types.ts +6 -0
- package/lib/commonjs/utils.js +0 -9
- package/lib/commonjs/utils.js.map +0 -1
- package/lib/module/utils.js +0 -2
- package/lib/module/utils.js.map +0 -1
- package/lib/typescript/utils.d.ts +0 -1
- package/src/utils.ts +0 -1
package/src/animated.tsx
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint react/jsx-sort-props: off */
|
|
2
|
+
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
2
3
|
import { Animated, Platform, StyleSheet } from "react-native";
|
|
3
4
|
import Reanimated, { useSharedValue } from "react-native-reanimated";
|
|
4
5
|
|
|
5
6
|
import { KeyboardControllerView } from "./bindings";
|
|
6
7
|
import { KeyboardContext } from "./context";
|
|
7
|
-
import {
|
|
8
|
+
import { focusedInputEventsMap, keyboardEventsMap } from "./event-mappings";
|
|
9
|
+
import { useAnimatedValue, useEventHandlerRegistration } from "./internal";
|
|
8
10
|
import { applyMonkeyPatch, revertMonkeyPatch } from "./monkey-patch";
|
|
9
11
|
import {
|
|
10
12
|
useAnimatedKeyboardHandler,
|
|
11
13
|
useFocusedInputLayoutHandler,
|
|
12
|
-
useFocusedInputSelectionHandler,
|
|
13
|
-
useFocusedInputTextHandler,
|
|
14
14
|
} from "./reanimated";
|
|
15
15
|
|
|
16
16
|
import type { KeyboardAnimationContext } from "./context";
|
|
@@ -24,9 +24,7 @@ import type {
|
|
|
24
24
|
import type { ViewStyle } from "react-native";
|
|
25
25
|
|
|
26
26
|
const KeyboardControllerViewAnimated = Reanimated.createAnimatedComponent(
|
|
27
|
-
Animated.createAnimatedComponent(
|
|
28
|
-
KeyboardControllerView,
|
|
29
|
-
) as React.FC<KeyboardControllerProps>,
|
|
27
|
+
Animated.createAnimatedComponent(KeyboardControllerView),
|
|
30
28
|
);
|
|
31
29
|
|
|
32
30
|
type Styles = {
|
|
@@ -83,6 +81,8 @@ export const KeyboardProvider = ({
|
|
|
83
81
|
navigationBarTranslucent,
|
|
84
82
|
enabled: initiallyEnabled = true,
|
|
85
83
|
}: KeyboardProviderProps) => {
|
|
84
|
+
// ref
|
|
85
|
+
const viewTagRef = useRef<React.Component<KeyboardControllerProps>>(null);
|
|
86
86
|
// state
|
|
87
87
|
const [enabled, setEnabled] = useState(initiallyEnabled);
|
|
88
88
|
// animated values
|
|
@@ -92,10 +92,14 @@ export const KeyboardProvider = ({
|
|
|
92
92
|
const progressSV = useSharedValue(0);
|
|
93
93
|
const heightSV = useSharedValue(0);
|
|
94
94
|
const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
const setKeyboardHandlers = useEventHandlerRegistration<KeyboardHandler>(
|
|
96
|
+
keyboardEventsMap,
|
|
97
|
+
viewTagRef,
|
|
98
|
+
);
|
|
99
|
+
const setInputHandlers = useEventHandlerRegistration<FocusedInputHandler>(
|
|
100
|
+
focusedInputEventsMap,
|
|
101
|
+
viewTagRef,
|
|
102
|
+
);
|
|
99
103
|
// memo
|
|
100
104
|
const context = useMemo<KeyboardAnimationContext>(
|
|
101
105
|
() => ({
|
|
@@ -136,6 +140,7 @@ export const KeyboardProvider = ({
|
|
|
136
140
|
"worklet";
|
|
137
141
|
|
|
138
142
|
if (platforms.includes(OS)) {
|
|
143
|
+
// eslint-disable-next-line react-compiler/react-compiler
|
|
139
144
|
progressSV.value = event.progress;
|
|
140
145
|
heightSV.value = -event.height;
|
|
141
146
|
}
|
|
@@ -145,25 +150,17 @@ export const KeyboardProvider = ({
|
|
|
145
150
|
onKeyboardMoveStart: (event: NativeEvent) => {
|
|
146
151
|
"worklet";
|
|
147
152
|
|
|
148
|
-
broadcastKeyboardEvents("onStart", event);
|
|
149
153
|
updateSharedValues(event, ["ios"]);
|
|
150
154
|
},
|
|
151
155
|
onKeyboardMove: (event: NativeEvent) => {
|
|
152
156
|
"worklet";
|
|
153
157
|
|
|
154
|
-
broadcastKeyboardEvents("onMove", event);
|
|
155
158
|
updateSharedValues(event, ["android"]);
|
|
156
159
|
},
|
|
157
|
-
onKeyboardMoveEnd: (event: NativeEvent) => {
|
|
158
|
-
"worklet";
|
|
159
|
-
|
|
160
|
-
broadcastKeyboardEvents("onEnd", event);
|
|
161
|
-
},
|
|
162
160
|
onKeyboardMoveInteractive: (event: NativeEvent) => {
|
|
163
161
|
"worklet";
|
|
164
162
|
|
|
165
163
|
updateSharedValues(event, ["android", "ios"]);
|
|
166
|
-
broadcastKeyboardEvents("onInteractive", event);
|
|
167
164
|
},
|
|
168
165
|
},
|
|
169
166
|
[],
|
|
@@ -182,26 +179,7 @@ export const KeyboardProvider = ({
|
|
|
182
179
|
},
|
|
183
180
|
[],
|
|
184
181
|
);
|
|
185
|
-
const inputTextHandler = useFocusedInputTextHandler(
|
|
186
|
-
{
|
|
187
|
-
onFocusedInputTextChanged: (e) => {
|
|
188
|
-
"worklet";
|
|
189
|
-
|
|
190
|
-
broadcastInputEvents("onChangeText", e);
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
[],
|
|
194
|
-
);
|
|
195
|
-
const inputSelectionHandler = useFocusedInputSelectionHandler(
|
|
196
|
-
{
|
|
197
|
-
onFocusedInputSelectionChanged: (e) => {
|
|
198
|
-
"worklet";
|
|
199
182
|
|
|
200
|
-
broadcastInputEvents("onSelectionChange", e);
|
|
201
|
-
},
|
|
202
|
-
},
|
|
203
|
-
[],
|
|
204
|
-
);
|
|
205
183
|
// effects
|
|
206
184
|
useEffect(() => {
|
|
207
185
|
if (enabled) {
|
|
@@ -214,17 +192,17 @@ export const KeyboardProvider = ({
|
|
|
214
192
|
return (
|
|
215
193
|
<KeyboardContext.Provider value={context}>
|
|
216
194
|
<KeyboardControllerViewAnimated
|
|
195
|
+
ref={viewTagRef}
|
|
217
196
|
enabled={enabled}
|
|
197
|
+
navigationBarTranslucent={navigationBarTranslucent}
|
|
198
|
+
statusBarTranslucent={statusBarTranslucent}
|
|
199
|
+
style={styles.container}
|
|
200
|
+
// on*Reanimated prop must precede animated handlers to work correctly
|
|
218
201
|
onKeyboardMoveReanimated={keyboardHandler}
|
|
219
202
|
onKeyboardMoveStart={OS === "ios" ? onKeyboardMove : undefined}
|
|
220
203
|
onKeyboardMove={OS === "android" ? onKeyboardMove : undefined}
|
|
221
204
|
onKeyboardMoveInteractive={onKeyboardMove}
|
|
222
205
|
onFocusedInputLayoutChangedReanimated={inputLayoutHandler}
|
|
223
|
-
onFocusedInputTextChangedReanimated={inputTextHandler}
|
|
224
|
-
onFocusedInputSelectionChangedReanimated={inputSelectionHandler}
|
|
225
|
-
navigationBarTranslucent={navigationBarTranslucent}
|
|
226
|
-
statusBarTranslucent={statusBarTranslucent}
|
|
227
|
-
style={styles.container}
|
|
228
206
|
>
|
|
229
207
|
{children}
|
|
230
208
|
</KeyboardControllerViewAnimated>
|
package/src/bindings.native.ts
CHANGED
package/src/bindings.ts
CHANGED
|
@@ -18,6 +18,7 @@ export const useKeyboardAnimation = () => {
|
|
|
18
18
|
"worklet";
|
|
19
19
|
|
|
20
20
|
if (e.height > 0) {
|
|
21
|
+
// eslint-disable-next-line react-compiler/react-compiler
|
|
21
22
|
isClosed.value = false;
|
|
22
23
|
heightWhenOpened.value = e.height;
|
|
23
24
|
}
|
|
@@ -33,19 +34,8 @@ export const useKeyboardAnimation = () => {
|
|
|
33
34
|
|
|
34
35
|
isClosed.value = e.height === 0;
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// wasn't called (i. e. duration === 0)
|
|
39
|
-
//
|
|
40
|
-
// we can not call this code without condition below
|
|
41
|
-
// because in some corner cases (iOS with `secureTextEntry`)
|
|
42
|
-
// `onEnd` can be emitted before `onMove` and in this case
|
|
43
|
-
// it may lead to choppy/glitchy/jumpy UI
|
|
44
|
-
// see https://github.com/kirillzyusko/react-native-keyboard-controller/issues/327
|
|
45
|
-
if (e.duration === 0) {
|
|
46
|
-
progress.value = e.progress;
|
|
47
|
-
height.value = e.height;
|
|
48
|
-
}
|
|
37
|
+
height.value = e.height;
|
|
38
|
+
progress.value = e.progress;
|
|
49
39
|
},
|
|
50
40
|
},
|
|
51
41
|
[],
|
|
@@ -85,6 +85,7 @@ const KeyboardAvoidingView = forwardRef<
|
|
|
85
85
|
"worklet";
|
|
86
86
|
|
|
87
87
|
if (keyboard.isClosed.value || initialFrame.value === null) {
|
|
88
|
+
// eslint-disable-next-line react-compiler/react-compiler
|
|
88
89
|
initialFrame.value = layout;
|
|
89
90
|
}
|
|
90
91
|
}, []);
|
|
@@ -143,8 +144,8 @@ const KeyboardAvoidingView = forwardRef<
|
|
|
143
144
|
return (
|
|
144
145
|
<Reanimated.View
|
|
145
146
|
ref={ref}
|
|
146
|
-
onLayout={onLayout}
|
|
147
147
|
style={combinedStyles}
|
|
148
|
+
onLayout={onLayout}
|
|
148
149
|
{...props}
|
|
149
150
|
>
|
|
150
151
|
{children}
|
|
@@ -24,7 +24,10 @@ import type {
|
|
|
24
24
|
ScrollView,
|
|
25
25
|
ScrollViewProps,
|
|
26
26
|
} from "react-native";
|
|
27
|
-
import type {
|
|
27
|
+
import type {
|
|
28
|
+
FocusedInputLayoutChangedEvent,
|
|
29
|
+
FocusedInputSelectionChangedEvent,
|
|
30
|
+
} from "react-native-keyboard-controller";
|
|
28
31
|
|
|
29
32
|
export type KeyboardAwareScrollViewProps = {
|
|
30
33
|
/** The distance between keyboard and focused `TextInput` when keyboard is shown. Default is `0`. */
|
|
@@ -87,6 +90,7 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
87
90
|
disableScrollOnKeyboardHide = false,
|
|
88
91
|
enabled = true,
|
|
89
92
|
extraKeyboardSpace = 0,
|
|
93
|
+
snapToOffsets,
|
|
90
94
|
...rest
|
|
91
95
|
},
|
|
92
96
|
ref,
|
|
@@ -155,12 +159,13 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
155
159
|
0,
|
|
156
160
|
scrollDistanceWithRespectToSnapPoints(
|
|
157
161
|
relativeScrollTo + scrollPosition.value,
|
|
158
|
-
|
|
162
|
+
snapToOffsets,
|
|
159
163
|
) - scrollPosition.value,
|
|
160
164
|
],
|
|
161
165
|
);
|
|
162
166
|
const targetScrollY =
|
|
163
167
|
Math.max(interpolatedScrollTo, 0) + scrollPosition.value;
|
|
168
|
+
|
|
164
169
|
scrollTo(scrollViewAnimatedRef, 0, targetScrollY, animated);
|
|
165
170
|
|
|
166
171
|
return interpolatedScrollTo;
|
|
@@ -180,9 +185,35 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
180
185
|
|
|
181
186
|
return 0;
|
|
182
187
|
},
|
|
183
|
-
[bottomOffset, enabled, height,
|
|
188
|
+
[bottomOffset, enabled, height, snapToOffsets],
|
|
184
189
|
);
|
|
185
190
|
|
|
191
|
+
const scrollFromCurrentPosition = useCallback(
|
|
192
|
+
(customHeight?: number) => {
|
|
193
|
+
"worklet";
|
|
194
|
+
|
|
195
|
+
const prevScrollPosition = scrollPosition.value;
|
|
196
|
+
const prevLayout = layout.value;
|
|
197
|
+
|
|
198
|
+
if (!input.value?.layout) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// eslint-disable-next-line react-compiler/react-compiler
|
|
203
|
+
layout.value = {
|
|
204
|
+
...input.value,
|
|
205
|
+
layout: {
|
|
206
|
+
...input.value.layout,
|
|
207
|
+
height: customHeight ?? input.value.layout.height,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
scrollPosition.value = position.value;
|
|
211
|
+
maybeScroll(keyboardHeight.value, true);
|
|
212
|
+
scrollPosition.value = prevScrollPosition;
|
|
213
|
+
layout.value = prevLayout;
|
|
214
|
+
},
|
|
215
|
+
[maybeScroll],
|
|
216
|
+
);
|
|
186
217
|
const onChangeText = useCallback(() => {
|
|
187
218
|
"worklet";
|
|
188
219
|
|
|
@@ -192,15 +223,18 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
192
223
|
return;
|
|
193
224
|
}
|
|
194
225
|
|
|
195
|
-
|
|
196
|
-
|
|
226
|
+
scrollFromCurrentPosition();
|
|
227
|
+
}, [scrollFromCurrentPosition]);
|
|
228
|
+
const onSelectionChange = useCallback(
|
|
229
|
+
(e: FocusedInputSelectionChangedEvent) => {
|
|
230
|
+
"worklet";
|
|
197
231
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
232
|
+
if (e.selection.start.position !== e.selection.end.position) {
|
|
233
|
+
scrollFromCurrentPosition(e.selection.end.y);
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
[scrollFromCurrentPosition],
|
|
237
|
+
);
|
|
204
238
|
|
|
205
239
|
const onChangeTextHandler = useMemo(
|
|
206
240
|
() => debounce(onChangeText, 200),
|
|
@@ -210,8 +244,9 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
210
244
|
useFocusedInputHandler(
|
|
211
245
|
{
|
|
212
246
|
onChangeText: onChangeTextHandler,
|
|
247
|
+
onSelectionChange: onSelectionChange,
|
|
213
248
|
},
|
|
214
|
-
[onChangeTextHandler],
|
|
249
|
+
[onChangeTextHandler, onSelectionChange],
|
|
215
250
|
);
|
|
216
251
|
|
|
217
252
|
useSmoothKeyboardHandler(
|
|
@@ -221,7 +256,9 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
221
256
|
|
|
222
257
|
const keyboardWillChangeSize =
|
|
223
258
|
keyboardHeight.value !== e.height && e.height > 0;
|
|
259
|
+
|
|
224
260
|
keyboardWillAppear.value = e.height > 0 && keyboardHeight.value === 0;
|
|
261
|
+
|
|
225
262
|
const keyboardWillHide = e.height === 0;
|
|
226
263
|
const focusWasChanged =
|
|
227
264
|
(tag.value !== e.target && e.target !== -1) ||
|
|
@@ -273,6 +310,7 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
273
310
|
[0, keyboardHeight.value],
|
|
274
311
|
[0, keyboardHeight.value + extraKeyboardSpace],
|
|
275
312
|
);
|
|
313
|
+
|
|
276
314
|
currentKeyboardFrameHeight.value = keyboardFrame;
|
|
277
315
|
|
|
278
316
|
// if the user has set disableScrollOnKeyboardHide, only auto-scroll when the keyboard opens
|
|
@@ -327,8 +365,8 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
327
365
|
<Reanimated.ScrollView
|
|
328
366
|
ref={onRef}
|
|
329
367
|
{...rest}
|
|
330
|
-
onLayout={onScrollViewLayout}
|
|
331
368
|
scrollEventThrottle={16}
|
|
369
|
+
onLayout={onScrollViewLayout}
|
|
332
370
|
>
|
|
333
371
|
{children}
|
|
334
372
|
<Reanimated.View style={view} />
|
|
@@ -54,6 +54,7 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
|
|
|
54
54
|
height: animatedKeyboardHeight.value,
|
|
55
55
|
progress: animatedKeyboardHeight.value / persistedHeight.value,
|
|
56
56
|
};
|
|
57
|
+
|
|
57
58
|
return event;
|
|
58
59
|
},
|
|
59
60
|
(evt) => {
|
|
@@ -65,6 +66,7 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
|
|
|
65
66
|
// dispatch `onEnd`
|
|
66
67
|
if (evt.height === height.value) {
|
|
67
68
|
handler.onEnd?.(evt);
|
|
69
|
+
// eslint-disable-next-line react-compiler/react-compiler
|
|
68
70
|
persistedHeight.value = height.value;
|
|
69
71
|
}
|
|
70
72
|
},
|
|
@@ -10,11 +10,11 @@ import useColorScheme from "../hooks/useColorScheme";
|
|
|
10
10
|
|
|
11
11
|
import type { KeyboardToolbarTheme } from "./types";
|
|
12
12
|
import type { PropsWithChildren } from "react";
|
|
13
|
-
import type { ViewStyle } from "react-native";
|
|
13
|
+
import type { GestureResponderEvent, ViewStyle } from "react-native";
|
|
14
14
|
|
|
15
15
|
type ButtonProps = {
|
|
16
16
|
disabled?: boolean;
|
|
17
|
-
onPress: () => void;
|
|
17
|
+
onPress: (event: GestureResponderEvent) => void;
|
|
18
18
|
accessibilityLabel: string;
|
|
19
19
|
accessibilityHint: string;
|
|
20
20
|
testID: string;
|
|
@@ -41,13 +41,13 @@ const ButtonIOS = ({
|
|
|
41
41
|
|
|
42
42
|
return (
|
|
43
43
|
<Container
|
|
44
|
-
accessibilityState={accessibilityState}
|
|
45
|
-
accessibilityRole="button"
|
|
46
|
-
accessibilityLabel={accessibilityLabel}
|
|
47
44
|
accessibilityHint={accessibilityHint}
|
|
48
|
-
|
|
45
|
+
accessibilityLabel={accessibilityLabel}
|
|
46
|
+
accessibilityRole="button"
|
|
47
|
+
accessibilityState={accessibilityState}
|
|
49
48
|
style={style}
|
|
50
49
|
testID={testID}
|
|
50
|
+
onPress={onPress}
|
|
51
51
|
>
|
|
52
52
|
{children}
|
|
53
53
|
</Container>
|
|
@@ -78,14 +78,14 @@ const ButtonAndroid = ({
|
|
|
78
78
|
|
|
79
79
|
return (
|
|
80
80
|
<TouchableNativeFeedback
|
|
81
|
-
accessibilityState={accessibilityState}
|
|
82
|
-
accessibilityRole="button"
|
|
83
|
-
accessibilityLabel={accessibilityLabel}
|
|
84
81
|
accessibilityHint={accessibilityHint}
|
|
85
|
-
|
|
82
|
+
accessibilityLabel={accessibilityLabel}
|
|
83
|
+
accessibilityRole="button"
|
|
84
|
+
accessibilityState={accessibilityState}
|
|
86
85
|
background={ripple}
|
|
87
|
-
testID={testID}
|
|
88
86
|
style={style}
|
|
87
|
+
testID={testID}
|
|
88
|
+
onPress={onPress}
|
|
89
89
|
>
|
|
90
90
|
<View style={style}>{children}</View>
|
|
91
91
|
</TouchableNativeFeedback>
|
|
@@ -15,6 +15,7 @@ import { colors } from "./colors";
|
|
|
15
15
|
|
|
16
16
|
import type { HEX, KeyboardToolbarTheme } from "./types";
|
|
17
17
|
import type { ReactNode } from "react";
|
|
18
|
+
import type { GestureResponderEvent } from "react-native";
|
|
18
19
|
|
|
19
20
|
export type KeyboardToolbarProps = {
|
|
20
21
|
/** An element that is shown in the middle of the toolbar. */
|
|
@@ -35,15 +36,15 @@ export type KeyboardToolbarProps = {
|
|
|
35
36
|
/**
|
|
36
37
|
* A callback that is called when the user presses the next button along with the default action.
|
|
37
38
|
*/
|
|
38
|
-
onNextCallback?: () => void;
|
|
39
|
+
onNextCallback?: (event: GestureResponderEvent) => void;
|
|
39
40
|
/**
|
|
40
41
|
* A callback that is called when the user presses the previous button along with the default action.
|
|
41
42
|
*/
|
|
42
|
-
onPrevCallback?: () => void;
|
|
43
|
+
onPrevCallback?: (event: GestureResponderEvent) => void;
|
|
43
44
|
/**
|
|
44
45
|
* A callback that is called when the user presses the done button along with the default action.
|
|
45
46
|
*/
|
|
46
|
-
onDoneCallback?: () => void;
|
|
47
|
+
onDoneCallback?: (event: GestureResponderEvent) => void;
|
|
47
48
|
/**
|
|
48
49
|
* A component that applies blur effect to the toolbar.
|
|
49
50
|
*/
|
|
@@ -53,6 +54,7 @@ export type KeyboardToolbarProps = {
|
|
|
53
54
|
*/
|
|
54
55
|
opacity?: HEX;
|
|
55
56
|
};
|
|
57
|
+
|
|
56
58
|
const TEST_ID_KEYBOARD_TOOLBAR = "keyboard.toolbar";
|
|
57
59
|
const TEST_ID_KEYBOARD_TOOLBAR_PREVIOUS = `${TEST_ID_KEYBOARD_TOOLBAR}.previous`;
|
|
58
60
|
const TEST_ID_KEYBOARD_TOOLBAR_NEXT = `${TEST_ID_KEYBOARD_TOOLBAR}.next`;
|
|
@@ -115,18 +117,36 @@ const KeyboardToolbar: React.FC<KeyboardToolbarProps> = ({
|
|
|
115
117
|
const ButtonContainer = button || Button;
|
|
116
118
|
const IconContainer = icon || Arrow;
|
|
117
119
|
|
|
118
|
-
const onPressNext = useCallback(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
120
|
+
const onPressNext = useCallback(
|
|
121
|
+
(event: GestureResponderEvent) => {
|
|
122
|
+
onNextCallback?.(event);
|
|
123
|
+
|
|
124
|
+
if (!event.isDefaultPrevented()) {
|
|
125
|
+
goToNextField();
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
[onNextCallback],
|
|
129
|
+
);
|
|
130
|
+
const onPressPrev = useCallback(
|
|
131
|
+
(event: GestureResponderEvent) => {
|
|
132
|
+
onPrevCallback?.(event);
|
|
133
|
+
|
|
134
|
+
if (!event.isDefaultPrevented()) {
|
|
135
|
+
goToPrevField();
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
[onPrevCallback],
|
|
139
|
+
);
|
|
140
|
+
const onPressDone = useCallback(
|
|
141
|
+
(event: GestureResponderEvent) => {
|
|
142
|
+
onDoneCallback?.(event);
|
|
143
|
+
|
|
144
|
+
if (!event.isDefaultPrevented()) {
|
|
145
|
+
dismissKeyboard();
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
[onDoneCallback],
|
|
149
|
+
);
|
|
130
150
|
|
|
131
151
|
return (
|
|
132
152
|
<KeyboardStickyView offset={offset}>
|
|
@@ -135,31 +155,31 @@ const KeyboardToolbar: React.FC<KeyboardToolbarProps> = ({
|
|
|
135
155
|
{showArrows && (
|
|
136
156
|
<>
|
|
137
157
|
<ButtonContainer
|
|
158
|
+
accessibilityHint="Moves focus to the previous field"
|
|
138
159
|
accessibilityLabel="Previous"
|
|
139
|
-
accessibilityHint="Will move focus to previous field"
|
|
140
160
|
disabled={isPrevDisabled}
|
|
141
|
-
onPress={onPressPrev}
|
|
142
161
|
testID={TEST_ID_KEYBOARD_TOOLBAR_PREVIOUS}
|
|
143
162
|
theme={theme}
|
|
163
|
+
onPress={onPressPrev}
|
|
144
164
|
>
|
|
145
165
|
<IconContainer
|
|
146
166
|
disabled={isPrevDisabled}
|
|
147
|
-
type="prev"
|
|
148
167
|
theme={theme}
|
|
168
|
+
type="prev"
|
|
149
169
|
/>
|
|
150
170
|
</ButtonContainer>
|
|
151
171
|
<ButtonContainer
|
|
172
|
+
accessibilityHint="Moves focus to the next field"
|
|
152
173
|
accessibilityLabel="Next"
|
|
153
|
-
accessibilityHint="Will move focus to next field"
|
|
154
174
|
disabled={isNextDisabled}
|
|
155
|
-
onPress={onPressNext}
|
|
156
175
|
testID={TEST_ID_KEYBOARD_TOOLBAR_NEXT}
|
|
157
176
|
theme={theme}
|
|
177
|
+
onPress={onPressNext}
|
|
158
178
|
>
|
|
159
179
|
<IconContainer
|
|
160
180
|
disabled={isNextDisabled}
|
|
161
|
-
type="next"
|
|
162
181
|
theme={theme}
|
|
182
|
+
type="next"
|
|
163
183
|
/>
|
|
164
184
|
</ButtonContainer>
|
|
165
185
|
</>
|
|
@@ -169,15 +189,15 @@ const KeyboardToolbar: React.FC<KeyboardToolbarProps> = ({
|
|
|
169
189
|
{content}
|
|
170
190
|
</View>
|
|
171
191
|
<ButtonContainer
|
|
192
|
+
accessibilityHint="Closes the keyboard"
|
|
172
193
|
accessibilityLabel="Done"
|
|
173
|
-
accessibilityHint="Will close the keyboard"
|
|
174
|
-
onPress={onPressDone}
|
|
175
|
-
testID={TEST_ID_KEYBOARD_TOOLBAR_DONE}
|
|
176
194
|
rippleRadius={28}
|
|
177
195
|
style={styles.doneButtonContainer}
|
|
196
|
+
testID={TEST_ID_KEYBOARD_TOOLBAR_DONE}
|
|
178
197
|
theme={theme}
|
|
198
|
+
onPress={onPressDone}
|
|
179
199
|
>
|
|
180
|
-
<Text
|
|
200
|
+
<Text maxFontSizeMultiplier={1.3} style={doneStyle}>
|
|
181
201
|
{doneText || "Done"}
|
|
182
202
|
</Text>
|
|
183
203
|
</ButtonContainer>
|
package/src/context.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { createContext, useContext } from "react";
|
|
|
2
2
|
import { Animated } from "react-native";
|
|
3
3
|
|
|
4
4
|
import type {
|
|
5
|
-
|
|
5
|
+
FocusedInputHandler,
|
|
6
6
|
FocusedInputLayoutChangedEvent,
|
|
7
|
-
|
|
7
|
+
KeyboardHandler,
|
|
8
8
|
} from "./types";
|
|
9
9
|
import type React from "react";
|
|
10
10
|
import type { SharedValue } from "react-native-reanimated";
|
|
@@ -22,11 +22,12 @@ export type KeyboardAnimationContext = {
|
|
|
22
22
|
animated: AnimatedContext;
|
|
23
23
|
reanimated: ReanimatedContext;
|
|
24
24
|
layout: SharedValue<FocusedInputLayoutChangedEvent | null>;
|
|
25
|
-
setKeyboardHandlers: (handlers:
|
|
26
|
-
setInputHandlers: (handlers:
|
|
25
|
+
setKeyboardHandlers: (handlers: KeyboardHandler) => () => void;
|
|
26
|
+
setInputHandlers: (handlers: FocusedInputHandler) => () => void;
|
|
27
27
|
setEnabled: React.Dispatch<React.SetStateAction<boolean>>;
|
|
28
28
|
};
|
|
29
29
|
const NOOP = () => {};
|
|
30
|
+
const NESTED_NOOP = () => NOOP;
|
|
30
31
|
const withSharedValue = <T>(value: T): SharedValue<T> => ({
|
|
31
32
|
value,
|
|
32
33
|
addListener: NOOP,
|
|
@@ -48,10 +49,11 @@ const defaultContext: KeyboardAnimationContext = {
|
|
|
48
49
|
height: DEFAULT_SHARED_VALUE,
|
|
49
50
|
},
|
|
50
51
|
layout: DEFAULT_LAYOUT,
|
|
51
|
-
setKeyboardHandlers:
|
|
52
|
-
setInputHandlers:
|
|
52
|
+
setKeyboardHandlers: NESTED_NOOP,
|
|
53
|
+
setInputHandlers: NESTED_NOOP,
|
|
53
54
|
setEnabled: NOOP,
|
|
54
55
|
};
|
|
56
|
+
|
|
55
57
|
export const KeyboardContext = createContext(defaultContext);
|
|
56
58
|
export const useKeyboardContext = () => {
|
|
57
59
|
const context = useContext(KeyboardContext);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
let REACore = null;
|
|
2
|
+
|
|
3
|
+
try {
|
|
4
|
+
REACore = require("react-native-reanimated/src/core");
|
|
5
|
+
} catch (e1) {
|
|
6
|
+
try {
|
|
7
|
+
REACore = require("react-native-reanimated/src/reanimated2/core");
|
|
8
|
+
} catch (e2) {
|
|
9
|
+
console.warn("Failed to load REACore from both paths");
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const registerEventHandler = REACore.registerEventHandler;
|
|
13
|
+
const unregisterEventHandler = REACore.unregisterEventHandler;
|
|
14
|
+
|
|
15
|
+
export { registerEventHandler, unregisterEventHandler };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FocusedInputHandler, KeyboardHandler } from "./types";
|
|
2
|
+
|
|
3
|
+
export const keyboardEventsMap = new Map<keyof KeyboardHandler, string>([
|
|
4
|
+
["onStart", "onKeyboardMoveStart"],
|
|
5
|
+
["onMove", "onKeyboardMove"],
|
|
6
|
+
["onEnd", "onKeyboardMoveEnd"],
|
|
7
|
+
["onInteractive", "onKeyboardMoveInteractive"],
|
|
8
|
+
]);
|
|
9
|
+
export const focusedInputEventsMap = new Map<keyof FocusedInputHandler, string>(
|
|
10
|
+
[
|
|
11
|
+
["onChangeText", "onFocusedInputTextChanged"],
|
|
12
|
+
["onSelectionChange", "onFocusedInputSelectionChanged"],
|
|
13
|
+
],
|
|
14
|
+
);
|