react-native-keyboard-controller 1.10.0 → 1.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt +31 -1
- package/ios/.clang-format +30 -30
- package/ios/.swiftlint.yml +1 -1
- package/ios/observers/FocusedInputObserver.swift +1 -0
- package/ios/views/KeyboardControllerViewManager.swift +12 -2
- package/jest/index.js +14 -4
- package/lib/commonjs/animated.js +19 -19
- package/lib/commonjs/animated.js.map +1 -1
- package/lib/commonjs/bindings.js.map +1 -1
- package/lib/commonjs/bindings.native.js +6 -6
- package/lib/commonjs/bindings.native.js.map +1 -1
- package/lib/commonjs/components/KeyboardAvoidingView/hooks.js +19 -5
- package/lib/commonjs/components/KeyboardAvoidingView/hooks.js.map +1 -1
- package/lib/commonjs/components/KeyboardAvoidingView/index.js +12 -7
- package/lib/commonjs/components/KeyboardAvoidingView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js +10 -8
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js +5 -5
- package/lib/commonjs/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/utils.js +2 -2
- package/lib/commonjs/components/KeyboardAwareScrollView/utils.js.map +1 -1
- package/lib/commonjs/components/KeyboardStickyView/index.js +9 -5
- package/lib/commonjs/components/KeyboardStickyView/index.js.map +1 -1
- package/lib/commonjs/components/hooks/useKeyboardInterpolation.js +88 -0
- package/lib/commonjs/components/hooks/useKeyboardInterpolation.js.map +1 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/constants.js.map +1 -1
- package/lib/commonjs/context.js.map +1 -1
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/internal.js +1 -1
- 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.map +1 -1
- package/lib/commonjs/reanimated.native.js +12 -12
- package/lib/commonjs/reanimated.native.js.map +1 -1
- package/lib/commonjs/replicas.js +5 -5
- package/lib/commonjs/replicas.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 +2 -2
- package/lib/commonjs/specs/KeyboardGestureAreaNativeComponent.js.map +1 -1
- package/lib/commonjs/specs/NativeKeyboardController.js +1 -1
- package/lib/commonjs/specs/NativeKeyboardController.js.map +1 -1
- package/lib/commonjs/specs/NativeStatusBarManagerCompat.js +1 -1
- package/lib/commonjs/specs/NativeStatusBarManagerCompat.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/utils.js.map +1 -1
- package/lib/module/animated.js +27 -27
- package/lib/module/animated.js.map +1 -1
- package/lib/module/bindings.js +1 -1
- package/lib/module/bindings.js.map +1 -1
- package/lib/module/bindings.native.js +7 -7
- package/lib/module/bindings.native.js.map +1 -1
- package/lib/module/components/KeyboardAvoidingView/hooks.js +19 -5
- package/lib/module/components/KeyboardAvoidingView/hooks.js.map +1 -1
- package/lib/module/components/KeyboardAvoidingView/index.js +15 -11
- package/lib/module/components/KeyboardAvoidingView/index.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/index.js +16 -14
- package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js +8 -8
- package/lib/module/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/utils.js +2 -2
- package/lib/module/components/KeyboardAwareScrollView/utils.js.map +1 -1
- package/lib/module/components/KeyboardStickyView/index.js +9 -6
- package/lib/module/components/KeyboardStickyView/index.js.map +1 -1
- package/lib/module/components/hooks/useKeyboardInterpolation.js +81 -0
- package/lib/module/components/hooks/useKeyboardInterpolation.js.map +1 -0
- package/lib/module/components/index.js +3 -3
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/context.js +2 -2
- package/lib/module/context.js.map +1 -1
- package/lib/module/hooks.js +5 -5
- package/lib/module/hooks.js.map +1 -1
- package/lib/module/index.js +8 -8
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal.js +4 -4
- package/lib/module/internal.js.map +1 -1
- package/lib/module/monkey-patch.android.js +2 -2
- package/lib/module/monkey-patch.android.js.map +1 -1
- package/lib/module/monkey-patch.js.map +1 -1
- package/lib/module/reanimated.js.map +1 -1
- package/lib/module/reanimated.native.js +13 -13
- package/lib/module/reanimated.native.js.map +1 -1
- package/lib/module/replicas.js +11 -11
- package/lib/module/replicas.js.map +1 -1
- package/lib/module/specs/KeyboardControllerViewNativeComponent.js +2 -2
- package/lib/module/specs/KeyboardControllerViewNativeComponent.js.map +1 -1
- package/lib/module/specs/KeyboardGestureAreaNativeComponent.js +3 -3
- package/lib/module/specs/KeyboardGestureAreaNativeComponent.js.map +1 -1
- package/lib/module/specs/NativeKeyboardController.js +2 -2
- package/lib/module/specs/NativeKeyboardController.js.map +1 -1
- package/lib/module/specs/NativeStatusBarManagerCompat.js +2 -2
- package/lib/module/specs/NativeStatusBarManagerCompat.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils.js.map +1 -1
- package/lib/typescript/animated.d.ts +1 -1
- package/lib/typescript/bindings.d.ts +1 -1
- package/lib/typescript/bindings.native.d.ts +1 -1
- package/lib/typescript/components/KeyboardAvoidingView/index.d.ts +4 -4
- package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +2 -2
- package/lib/typescript/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.d.ts +1 -1
- package/lib/typescript/components/KeyboardStickyView/index.d.ts +2 -2
- package/lib/typescript/components/hooks/useKeyboardInterpolation.d.ts +20 -0
- package/lib/typescript/components/index.d.ts +3 -3
- package/lib/typescript/context.d.ts +4 -4
- package/lib/typescript/hooks.d.ts +3 -3
- package/lib/typescript/index.d.ts +8 -8
- package/lib/typescript/internal.d.ts +2 -2
- package/lib/typescript/reanimated.d.ts +1 -1
- package/lib/typescript/reanimated.native.d.ts +1 -1
- package/lib/typescript/replicas.d.ts +1 -1
- package/lib/typescript/specs/KeyboardControllerViewNativeComponent.d.ts +3 -3
- package/lib/typescript/specs/KeyboardGestureAreaNativeComponent.d.ts +4 -4
- package/lib/typescript/specs/NativeKeyboardController.d.ts +1 -1
- package/lib/typescript/specs/NativeStatusBarManagerCompat.d.ts +1 -1
- package/lib/typescript/types.d.ts +3 -3
- package/package.json +8 -10
- package/src/animated.tsx +39 -39
- package/src/bindings.native.ts +11 -11
- package/src/bindings.ts +3 -3
- package/src/components/KeyboardAvoidingView/hooks.ts +20 -6
- package/src/components/KeyboardAvoidingView/index.tsx +25 -24
- package/src/components/KeyboardAwareScrollView/index.tsx +29 -25
- package/src/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.ts +13 -13
- package/src/components/KeyboardAwareScrollView/utils.ts +3 -3
- package/src/components/KeyboardStickyView/index.tsx +12 -12
- package/src/components/hooks/useKeyboardInterpolation.ts +108 -0
- package/src/components/index.ts +3 -3
- package/src/context.ts +7 -7
- package/src/hooks.ts +12 -12
- package/src/index.ts +8 -8
- package/src/internal.ts +9 -9
- package/src/monkey-patch.android.ts +2 -2
- package/src/reanimated.native.ts +20 -20
- package/src/reanimated.ts +1 -1
- package/src/replicas.ts +16 -16
- package/src/specs/KeyboardControllerViewNativeComponent.ts +5 -5
- package/src/specs/KeyboardGestureAreaNativeComponent.ts +7 -7
- package/src/specs/NativeKeyboardController.ts +3 -3
- package/src/specs/NativeStatusBarManagerCompat.ts +3 -3
- package/src/types.ts +21 -21
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
import React, { forwardRef, useCallback, useMemo } from
|
|
2
|
-
import { View, useWindowDimensions } from
|
|
1
|
+
import React, { forwardRef, useCallback, useMemo } from "react";
|
|
2
|
+
import { View, useWindowDimensions } from "react-native";
|
|
3
3
|
import Reanimated, {
|
|
4
|
-
interpolate,
|
|
5
4
|
runOnUI,
|
|
6
5
|
useAnimatedStyle,
|
|
7
6
|
useDerivedValue,
|
|
8
7
|
useSharedValue,
|
|
9
|
-
} from
|
|
8
|
+
} from "react-native-reanimated";
|
|
10
9
|
|
|
11
|
-
import
|
|
10
|
+
import useKeyboardInterpolation from "../hooks/useKeyboardInterpolation";
|
|
12
11
|
|
|
13
|
-
import
|
|
12
|
+
import { useKeyboardAnimation } from "./hooks";
|
|
13
|
+
|
|
14
|
+
import type { LayoutRectangle, ViewProps } from "react-native";
|
|
14
15
|
|
|
15
16
|
type Props = {
|
|
16
17
|
/**
|
|
17
18
|
* Specify how to react to the presence of the keyboard.
|
|
18
19
|
*/
|
|
19
|
-
behavior?:
|
|
20
|
+
behavior?: "height" | "position" | "padding";
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Style of the content container when `behavior` is 'position'.
|
|
23
24
|
*/
|
|
24
|
-
contentContainerStyle?: ViewProps[
|
|
25
|
+
contentContainerStyle?: ViewProps["style"];
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Controls whether this `KeyboardAvoidingView` instance should take effect.
|
|
@@ -59,7 +60,7 @@ const KeyboardAvoidingView = forwardRef<View, React.PropsWithChildren<Props>>(
|
|
|
59
60
|
onLayout: onLayoutProps,
|
|
60
61
|
...props
|
|
61
62
|
},
|
|
62
|
-
ref
|
|
63
|
+
ref,
|
|
63
64
|
) => {
|
|
64
65
|
const initialFrame = useSharedValue<LayoutRectangle | null>(null);
|
|
65
66
|
const frame = useDerivedValue(() => initialFrame.value || defaultLayout);
|
|
@@ -68,39 +69,39 @@ const KeyboardAvoidingView = forwardRef<View, React.PropsWithChildren<Props>>(
|
|
|
68
69
|
const { height: screenHeight } = useWindowDimensions();
|
|
69
70
|
|
|
70
71
|
const relativeKeyboardHeight = useCallback(() => {
|
|
71
|
-
|
|
72
|
+
"worklet";
|
|
72
73
|
|
|
73
74
|
const keyboardY =
|
|
74
75
|
screenHeight - keyboard.heightWhenOpened.value - keyboardVerticalOffset;
|
|
75
76
|
|
|
76
77
|
return Math.max(frame.value.y + frame.value.height - keyboardY, 0);
|
|
77
78
|
}, [screenHeight, keyboardVerticalOffset]);
|
|
79
|
+
const { interpolate } = useKeyboardInterpolation();
|
|
78
80
|
|
|
79
81
|
const onLayoutWorklet = useCallback((layout: LayoutRectangle) => {
|
|
80
|
-
|
|
82
|
+
"worklet";
|
|
81
83
|
|
|
82
84
|
if (keyboard.isClosed.value) {
|
|
83
85
|
initialFrame.value = layout;
|
|
84
86
|
}
|
|
85
87
|
}, []);
|
|
86
|
-
const onLayout = useCallback<NonNullable<ViewProps[
|
|
88
|
+
const onLayout = useCallback<NonNullable<ViewProps["onLayout"]>>(
|
|
87
89
|
(e) => {
|
|
88
90
|
runOnUI(onLayoutWorklet)(e.nativeEvent.layout);
|
|
89
91
|
onLayoutProps?.(e);
|
|
90
92
|
},
|
|
91
|
-
[onLayoutProps]
|
|
93
|
+
[onLayoutProps],
|
|
92
94
|
);
|
|
93
95
|
|
|
94
96
|
const animatedStyle = useAnimatedStyle(() => {
|
|
95
|
-
const bottom = interpolate(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
);
|
|
97
|
+
const bottom = interpolate(keyboard.height.value, [
|
|
98
|
+
0,
|
|
99
|
+
relativeKeyboardHeight(),
|
|
100
|
+
]);
|
|
100
101
|
const bottomHeight = enabled ? bottom : 0;
|
|
101
102
|
|
|
102
103
|
switch (behavior) {
|
|
103
|
-
case
|
|
104
|
+
case "height":
|
|
104
105
|
if (!keyboard.isClosed.value) {
|
|
105
106
|
return {
|
|
106
107
|
height: frame.value.height - bottomHeight,
|
|
@@ -110,21 +111,21 @@ const KeyboardAvoidingView = forwardRef<View, React.PropsWithChildren<Props>>(
|
|
|
110
111
|
|
|
111
112
|
return {};
|
|
112
113
|
|
|
113
|
-
case
|
|
114
|
+
case "position":
|
|
114
115
|
return { bottom: bottomHeight };
|
|
115
116
|
|
|
116
|
-
case
|
|
117
|
+
case "padding":
|
|
117
118
|
return { paddingBottom: bottomHeight };
|
|
118
119
|
|
|
119
120
|
default:
|
|
120
121
|
return {};
|
|
121
122
|
}
|
|
122
123
|
}, [behavior, enabled, relativeKeyboardHeight]);
|
|
123
|
-
const isPositionBehavior = behavior ===
|
|
124
|
+
const isPositionBehavior = behavior === "position";
|
|
124
125
|
const containerStyle = isPositionBehavior ? contentContainerStyle : style;
|
|
125
126
|
const combinedStyles = useMemo(
|
|
126
127
|
() => [containerStyle, animatedStyle],
|
|
127
|
-
[containerStyle, animatedStyle]
|
|
128
|
+
[containerStyle, animatedStyle],
|
|
128
129
|
);
|
|
129
130
|
|
|
130
131
|
if (isPositionBehavior) {
|
|
@@ -145,7 +146,7 @@ const KeyboardAvoidingView = forwardRef<View, React.PropsWithChildren<Props>>(
|
|
|
145
146
|
{children}
|
|
146
147
|
</Reanimated.View>
|
|
147
148
|
);
|
|
148
|
-
}
|
|
149
|
+
},
|
|
149
150
|
);
|
|
150
151
|
|
|
151
152
|
export default KeyboardAvoidingView;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { useCallback, useMemo } from
|
|
2
|
-
import { useWindowDimensions } from
|
|
1
|
+
import React, { useCallback, useMemo } from "react";
|
|
2
|
+
import { useWindowDimensions } from "react-native";
|
|
3
3
|
import Reanimated, {
|
|
4
4
|
interpolate,
|
|
5
5
|
scrollTo,
|
|
@@ -8,19 +8,19 @@ import Reanimated, {
|
|
|
8
8
|
useAnimatedScrollHandler,
|
|
9
9
|
useAnimatedStyle,
|
|
10
10
|
useSharedValue,
|
|
11
|
-
} from
|
|
11
|
+
} from "react-native-reanimated";
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
14
|
useFocusedInputHandler,
|
|
15
15
|
useReanimatedFocusedInput,
|
|
16
|
-
} from
|
|
16
|
+
} from "react-native-keyboard-controller";
|
|
17
17
|
|
|
18
|
-
import { useSmoothKeyboardHandler } from
|
|
19
|
-
import { debounce } from
|
|
18
|
+
import { useSmoothKeyboardHandler } from "./useSmoothKeyboardHandler";
|
|
19
|
+
import { debounce } from "./utils";
|
|
20
20
|
|
|
21
|
-
import type { FC } from
|
|
22
|
-
import type { ScrollViewProps } from
|
|
23
|
-
import type { FocusedInputLayoutChangedEvent } from
|
|
21
|
+
import type { FC } from "react";
|
|
22
|
+
import type { ScrollViewProps } from "react-native";
|
|
23
|
+
import type { FocusedInputLayoutChangedEvent } from "react-native-keyboard-controller";
|
|
24
24
|
|
|
25
25
|
type KeyboardAwareScrollViewProps = {
|
|
26
26
|
bottomOffset?: number;
|
|
@@ -72,6 +72,7 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
|
|
|
72
72
|
const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();
|
|
73
73
|
const scrollPosition = useSharedValue(0);
|
|
74
74
|
const position = useSharedValue(0);
|
|
75
|
+
const currentKeyboardFrameHeight = useSharedValue(0);
|
|
75
76
|
const keyboardHeight = useSharedValue(0);
|
|
76
77
|
const tag = useSharedValue(-1);
|
|
77
78
|
const initialKeyboardSize = useSharedValue(0);
|
|
@@ -87,7 +88,7 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
|
|
|
87
88
|
position.value = e.contentOffset.y;
|
|
88
89
|
},
|
|
89
90
|
},
|
|
90
|
-
[]
|
|
91
|
+
[],
|
|
91
92
|
);
|
|
92
93
|
|
|
93
94
|
/**
|
|
@@ -95,7 +96,7 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
|
|
|
95
96
|
*/
|
|
96
97
|
const maybeScroll = useCallback(
|
|
97
98
|
(e: number, animated: boolean = false) => {
|
|
98
|
-
|
|
99
|
+
"worklet";
|
|
99
100
|
|
|
100
101
|
const visibleRect = height - keyboardHeight.value;
|
|
101
102
|
const absoluteY = layout.value?.layout.absoluteY || 0;
|
|
@@ -106,7 +107,7 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
|
|
|
106
107
|
const interpolatedScrollTo = interpolate(
|
|
107
108
|
e,
|
|
108
109
|
[initialKeyboardSize.value, keyboardHeight.value],
|
|
109
|
-
[0, keyboardHeight.value - (height - point) + bottomOffset]
|
|
110
|
+
[0, keyboardHeight.value - (height - point) + bottomOffset],
|
|
110
111
|
);
|
|
111
112
|
const targetScrollY =
|
|
112
113
|
Math.max(interpolatedScrollTo, 0) + scrollPosition.value;
|
|
@@ -123,17 +124,17 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
|
|
|
123
124
|
scrollViewAnimatedRef,
|
|
124
125
|
0,
|
|
125
126
|
topOfScreen - positionOnScreen,
|
|
126
|
-
animated
|
|
127
|
+
animated,
|
|
127
128
|
);
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
return 0;
|
|
131
132
|
},
|
|
132
|
-
[bottomOffset]
|
|
133
|
+
[bottomOffset],
|
|
133
134
|
);
|
|
134
135
|
|
|
135
136
|
const onChangeText = useCallback(() => {
|
|
136
|
-
|
|
137
|
+
"worklet";
|
|
137
138
|
|
|
138
139
|
// if typing a text caused layout shift, then we need to ignore this handler
|
|
139
140
|
// because this event will be handled in `useAnimatedReaction` below
|
|
@@ -152,20 +153,20 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
|
|
|
152
153
|
}, [maybeScroll]);
|
|
153
154
|
const onChangeTextHandler = useMemo(
|
|
154
155
|
() => debounce(onChangeText, 200),
|
|
155
|
-
[onChangeText]
|
|
156
|
+
[onChangeText],
|
|
156
157
|
);
|
|
157
158
|
|
|
158
159
|
useFocusedInputHandler(
|
|
159
160
|
{
|
|
160
161
|
onChangeText: onChangeTextHandler,
|
|
161
162
|
},
|
|
162
|
-
[onChangeTextHandler]
|
|
163
|
+
[onChangeTextHandler],
|
|
163
164
|
);
|
|
164
165
|
|
|
165
166
|
useSmoothKeyboardHandler(
|
|
166
167
|
{
|
|
167
168
|
onStart: (e) => {
|
|
168
|
-
|
|
169
|
+
"worklet";
|
|
169
170
|
|
|
170
171
|
const keyboardWillChangeSize =
|
|
171
172
|
keyboardHeight.value !== e.height && e.height > 0;
|
|
@@ -209,18 +210,20 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
|
|
|
209
210
|
}
|
|
210
211
|
},
|
|
211
212
|
onMove: (e) => {
|
|
212
|
-
|
|
213
|
+
"worklet";
|
|
214
|
+
|
|
215
|
+
currentKeyboardFrameHeight.value = e.height;
|
|
213
216
|
|
|
214
217
|
maybeScroll(e.height);
|
|
215
218
|
},
|
|
216
219
|
onEnd: (e) => {
|
|
217
|
-
|
|
220
|
+
"worklet";
|
|
218
221
|
|
|
219
222
|
keyboardHeight.value = e.height;
|
|
220
223
|
scrollPosition.value = position.value;
|
|
221
224
|
},
|
|
222
225
|
},
|
|
223
|
-
[height, maybeScroll]
|
|
226
|
+
[height, maybeScroll],
|
|
224
227
|
);
|
|
225
228
|
|
|
226
229
|
useAnimatedReaction(
|
|
@@ -237,14 +240,14 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
|
|
|
237
240
|
layout.value = prevLayout;
|
|
238
241
|
}
|
|
239
242
|
},
|
|
240
|
-
[]
|
|
243
|
+
[],
|
|
241
244
|
);
|
|
242
245
|
|
|
243
246
|
const view = useAnimatedStyle(
|
|
244
247
|
() => ({
|
|
245
|
-
paddingBottom:
|
|
248
|
+
paddingBottom: currentKeyboardFrameHeight.value,
|
|
246
249
|
}),
|
|
247
|
-
[]
|
|
250
|
+
[],
|
|
248
251
|
);
|
|
249
252
|
|
|
250
253
|
return (
|
|
@@ -254,7 +257,8 @@ const KeyboardAwareScrollView: FC<KeyboardAwareScrollViewProps> = ({
|
|
|
254
257
|
onScroll={onScroll}
|
|
255
258
|
scrollEventThrottle={16}
|
|
256
259
|
>
|
|
257
|
-
|
|
260
|
+
{children}
|
|
261
|
+
<Reanimated.View style={view} />
|
|
258
262
|
</Reanimated.ScrollView>
|
|
259
263
|
);
|
|
260
264
|
};
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { Platform } from
|
|
1
|
+
import { Platform } from "react-native";
|
|
2
2
|
import {
|
|
3
3
|
Easing,
|
|
4
4
|
useAnimatedReaction,
|
|
5
5
|
useSharedValue,
|
|
6
6
|
withTiming,
|
|
7
|
-
} from
|
|
7
|
+
} from "react-native-reanimated";
|
|
8
8
|
|
|
9
|
-
import { useKeyboardHandler } from
|
|
9
|
+
import { useKeyboardHandler } from "react-native-keyboard-controller";
|
|
10
10
|
|
|
11
11
|
const IS_ANDROID_ELEVEN_OR_HIGHER =
|
|
12
|
-
Platform.OS ===
|
|
12
|
+
Platform.OS === "android" && Platform.Version >= 30;
|
|
13
13
|
// on these platforms keyboard transitions will be smooth
|
|
14
14
|
const IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS =
|
|
15
|
-
IS_ANDROID_ELEVEN_OR_HIGHER || Platform.OS ===
|
|
15
|
+
IS_ANDROID_ELEVEN_OR_HIGHER || Platform.OS === "ios";
|
|
16
16
|
// on Android Telegram is not using androidx.core values and uses custom interpolation
|
|
17
17
|
// duration is taken from here: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java#L39
|
|
18
18
|
// and bezier is taken from: https://github.com/DrKLO/Telegram/blob/e9a35cea54c06277c69d41b8e25d94b5d7ede065/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java#L40
|
|
@@ -22,7 +22,7 @@ const TELEGRAM_ANDROID_TIMING_CONFIG = {
|
|
|
22
22
|
0.19919472913616398,
|
|
23
23
|
0.010644531250000006,
|
|
24
24
|
0.27920937042459737,
|
|
25
|
-
0.91025390625
|
|
25
|
+
0.91025390625,
|
|
26
26
|
),
|
|
27
27
|
};
|
|
28
28
|
|
|
@@ -32,7 +32,7 @@ const TELEGRAM_ANDROID_TIMING_CONFIG = {
|
|
|
32
32
|
*/
|
|
33
33
|
export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
|
|
34
34
|
handler,
|
|
35
|
-
deps
|
|
35
|
+
deps,
|
|
36
36
|
) => {
|
|
37
37
|
const target = useSharedValue(-1);
|
|
38
38
|
const persistedHeight = useSharedValue(0);
|
|
@@ -64,13 +64,13 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
|
|
|
64
64
|
handler.onEnd?.(evt);
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
|
-
[handler]
|
|
67
|
+
[handler],
|
|
68
68
|
);
|
|
69
69
|
|
|
70
70
|
useKeyboardHandler(
|
|
71
71
|
{
|
|
72
72
|
onStart: (e) => {
|
|
73
|
-
|
|
73
|
+
"worklet";
|
|
74
74
|
|
|
75
75
|
// immediately dispatch onStart/onEnd events if onStart dispatched with the same height
|
|
76
76
|
// and don't wait for animation 250ms
|
|
@@ -95,21 +95,21 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
|
|
|
95
95
|
if (!IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
|
|
96
96
|
animatedKeyboardHeight.value = withTiming(
|
|
97
97
|
e.height,
|
|
98
|
-
TELEGRAM_ANDROID_TIMING_CONFIG
|
|
98
|
+
TELEGRAM_ANDROID_TIMING_CONFIG,
|
|
99
99
|
);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
handler.onStart?.(e);
|
|
103
103
|
},
|
|
104
104
|
onMove: (e) => {
|
|
105
|
-
|
|
105
|
+
"worklet";
|
|
106
106
|
|
|
107
107
|
if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
|
|
108
108
|
handler.onMove?.(e);
|
|
109
109
|
}
|
|
110
110
|
},
|
|
111
111
|
onEnd: (e) => {
|
|
112
|
-
|
|
112
|
+
"worklet";
|
|
113
113
|
|
|
114
114
|
if (IS_ANDROID_ELEVEN_OR_HIGHER_OR_IOS) {
|
|
115
115
|
handler.onEnd?.(e);
|
|
@@ -118,6 +118,6 @@ export const useSmoothKeyboardHandler: typeof useKeyboardHandler = (
|
|
|
118
118
|
persistedHeight.value = e.height;
|
|
119
119
|
},
|
|
120
120
|
},
|
|
121
|
-
deps
|
|
121
|
+
deps,
|
|
122
122
|
);
|
|
123
123
|
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export const debounce = <F extends (...args: Parameters<F>) => ReturnType<F>>(
|
|
2
2
|
worklet: F,
|
|
3
|
-
wait = 0
|
|
3
|
+
wait = 0,
|
|
4
4
|
) => {
|
|
5
|
-
|
|
5
|
+
"worklet";
|
|
6
6
|
|
|
7
7
|
const value = {
|
|
8
8
|
time: 0,
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
return (...args: Parameters<F>): ReturnType<F> | void => {
|
|
12
|
-
|
|
12
|
+
"worklet";
|
|
13
13
|
|
|
14
14
|
const t = Date.now();
|
|
15
15
|
const now = t - value.time;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import React, { forwardRef, useMemo } from
|
|
2
|
-
import Reanimated, {
|
|
3
|
-
interpolate,
|
|
4
|
-
useAnimatedStyle,
|
|
5
|
-
} from 'react-native-reanimated';
|
|
1
|
+
import React, { forwardRef, useMemo } from "react";
|
|
2
|
+
import Reanimated, { useAnimatedStyle } from "react-native-reanimated";
|
|
6
3
|
|
|
7
|
-
import { useReanimatedKeyboardAnimation } from
|
|
4
|
+
import { useReanimatedKeyboardAnimation } from "react-native-keyboard-controller";
|
|
8
5
|
|
|
9
|
-
import
|
|
6
|
+
import useKeyboardInterpolation from "../hooks/useKeyboardInterpolation";
|
|
7
|
+
|
|
8
|
+
import type { View, ViewProps } from "react-native";
|
|
10
9
|
|
|
11
10
|
type KeyboardStickyViewProps = {
|
|
12
11
|
/**
|
|
@@ -30,12 +29,13 @@ const KeyboardStickyView = forwardRef<
|
|
|
30
29
|
>(
|
|
31
30
|
(
|
|
32
31
|
{ children, offset: { closed = 0, opened = 0 } = {}, style, ...props },
|
|
33
|
-
ref
|
|
32
|
+
ref,
|
|
34
33
|
) => {
|
|
35
|
-
const { height
|
|
34
|
+
const { height } = useReanimatedKeyboardAnimation();
|
|
35
|
+
const { interpolate } = useKeyboardInterpolation();
|
|
36
36
|
|
|
37
37
|
const stickyViewStyle = useAnimatedStyle(() => {
|
|
38
|
-
const offset = interpolate(
|
|
38
|
+
const offset = interpolate(-height.value, [closed, opened]);
|
|
39
39
|
|
|
40
40
|
return {
|
|
41
41
|
transform: [{ translateY: height.value + offset }],
|
|
@@ -44,7 +44,7 @@ const KeyboardStickyView = forwardRef<
|
|
|
44
44
|
|
|
45
45
|
const styles = useMemo(
|
|
46
46
|
() => [style, stickyViewStyle],
|
|
47
|
-
[style, stickyViewStyle]
|
|
47
|
+
[style, stickyViewStyle],
|
|
48
48
|
);
|
|
49
49
|
|
|
50
50
|
return (
|
|
@@ -52,7 +52,7 @@ const KeyboardStickyView = forwardRef<
|
|
|
52
52
|
{children}
|
|
53
53
|
</Reanimated.View>
|
|
54
54
|
);
|
|
55
|
-
}
|
|
55
|
+
},
|
|
56
56
|
);
|
|
57
57
|
|
|
58
58
|
export default KeyboardStickyView;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Platform } from "react-native";
|
|
2
|
+
import {
|
|
3
|
+
interpolate as interpolateREA,
|
|
4
|
+
useSharedValue,
|
|
5
|
+
} from "react-native-reanimated";
|
|
6
|
+
|
|
7
|
+
import { useKeyboardHandler } from "react-native-keyboard-controller";
|
|
8
|
+
|
|
9
|
+
type KeyboardInterpolationOutput = [number, number];
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Hook that can be used for interpolation keyboard movement. The main concern is the thing
|
|
13
|
+
* when keyboard is opened and gets resized on Android. Let's say we are interpolating from
|
|
14
|
+
* closed to open [0, 200] and we want to interpolate it to [0, 230] (to achieve nice parallax effect).
|
|
15
|
+
* Then let's say keyboard changes its height to 220 (and we want to interpolate the value to 250, +30
|
|
16
|
+
* to keyboard height). If we interpolate based on `progress` value, then we will have a jump on first frame:
|
|
17
|
+
* the last interpolated position was 230, now we will interpolate to 250, but first frame will be calculated
|
|
18
|
+
* as 200 / 220 * 250 = 227 (and last interpolated position was 230) so we will have a jump.
|
|
19
|
+
*
|
|
20
|
+
* This hook handles it, and when keyboard changes its size it does an interpolation as:
|
|
21
|
+
* [200, 220] -> [230, 250], i. e. we preserve last interpolated value and use it as initial value for interpolation
|
|
22
|
+
* and because of that we will not have a jump and animation will start from the last frame and will be smooth.
|
|
23
|
+
*
|
|
24
|
+
* @see https://github.com/kirillzyusko/react-native-keyboard-controller/issues/315
|
|
25
|
+
*/
|
|
26
|
+
const useKeyboardInterpolation = () => {
|
|
27
|
+
// keyboard heights
|
|
28
|
+
const nextKeyboardHeight = useSharedValue(0);
|
|
29
|
+
const prevKeyboardHeight = useSharedValue(0);
|
|
30
|
+
// save latest interpolated position
|
|
31
|
+
const lastInterpolation = useSharedValue(0);
|
|
32
|
+
// boolean flag indicating which output range should be used
|
|
33
|
+
const shouldUseInternalInterpolation = useSharedValue(false);
|
|
34
|
+
|
|
35
|
+
const interpolate = (
|
|
36
|
+
keyboardPosition: number,
|
|
37
|
+
output: KeyboardInterpolationOutput,
|
|
38
|
+
) => {
|
|
39
|
+
"worklet";
|
|
40
|
+
|
|
41
|
+
// on iOS it's safe to interpolate between 0 and `fullKeyboardSize` because when
|
|
42
|
+
// keyboard resized we will not have intermediate values and transition will be instant
|
|
43
|
+
// see: https://github.com/kirillzyusko/react-native-keyboard-controller/issues/327
|
|
44
|
+
if (Platform.OS === "ios") {
|
|
45
|
+
return interpolateREA(
|
|
46
|
+
keyboardPosition,
|
|
47
|
+
[0, nextKeyboardHeight.value],
|
|
48
|
+
output,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
lastInterpolation.value = interpolateREA(
|
|
53
|
+
keyboardPosition,
|
|
54
|
+
[prevKeyboardHeight.value, nextKeyboardHeight.value],
|
|
55
|
+
shouldUseInternalInterpolation.value
|
|
56
|
+
? [lastInterpolation.value, output[1]]
|
|
57
|
+
: output,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return lastInterpolation.value;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
useKeyboardHandler(
|
|
64
|
+
{
|
|
65
|
+
onStart: (e) => {
|
|
66
|
+
"worklet";
|
|
67
|
+
|
|
68
|
+
const keyboardWillBeHidden = e.height === 0;
|
|
69
|
+
|
|
70
|
+
// keyboard will be hidden
|
|
71
|
+
if (keyboardWillBeHidden) {
|
|
72
|
+
shouldUseInternalInterpolation.value = false;
|
|
73
|
+
prevKeyboardHeight.value = 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// keyboard will change its size
|
|
77
|
+
if (
|
|
78
|
+
// keyboard is shown on screen
|
|
79
|
+
nextKeyboardHeight.value !== 0 &&
|
|
80
|
+
// it really changes size (handles iOS case when after interactive keyboard gets shown again)
|
|
81
|
+
nextKeyboardHeight.value !== e.height &&
|
|
82
|
+
// keyboard is not hiding
|
|
83
|
+
!keyboardWillBeHidden
|
|
84
|
+
) {
|
|
85
|
+
prevKeyboardHeight.value = nextKeyboardHeight.value;
|
|
86
|
+
shouldUseInternalInterpolation.value = true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// keyboard will show or change size
|
|
90
|
+
if (!keyboardWillBeHidden) {
|
|
91
|
+
nextKeyboardHeight.value = e.height;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
onEnd: (e) => {
|
|
95
|
+
"worklet";
|
|
96
|
+
|
|
97
|
+
// handles case show -> resize -> hide -> show
|
|
98
|
+
// here we reset value to 0 when keyboard is hidden
|
|
99
|
+
nextKeyboardHeight.value = e.height;
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
[],
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return { interpolate };
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export default useKeyboardInterpolation;
|
package/src/components/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { default as KeyboardAvoidingView } from
|
|
2
|
-
export { default as KeyboardStickyView } from
|
|
3
|
-
export { default as KeyboardAwareScrollView } from
|
|
1
|
+
export { default as KeyboardAvoidingView } from "./KeyboardAvoidingView";
|
|
2
|
+
export { default as KeyboardStickyView } from "./KeyboardStickyView";
|
|
3
|
+
export { default as KeyboardAwareScrollView } from "./KeyboardAwareScrollView";
|
package/src/context.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { createContext, useContext } from
|
|
2
|
-
import { Animated } from
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
import { Animated } from "react-native";
|
|
3
3
|
|
|
4
4
|
import type {
|
|
5
5
|
FocusedInputHandlers,
|
|
6
6
|
FocusedInputLayoutChangedEvent,
|
|
7
7
|
KeyboardHandlers,
|
|
8
|
-
} from
|
|
9
|
-
import type React from
|
|
10
|
-
import type { SharedValue } from
|
|
8
|
+
} from "./types";
|
|
9
|
+
import type React from "react";
|
|
10
|
+
import type { SharedValue } from "react-native-reanimated";
|
|
11
11
|
|
|
12
12
|
export type AnimatedContext = {
|
|
13
13
|
progress: Animated.Value;
|
|
@@ -35,7 +35,7 @@ const withSharedValue = <T>(value: T): SharedValue<T> => ({
|
|
|
35
35
|
});
|
|
36
36
|
const DEFAULT_SHARED_VALUE = withSharedValue(0);
|
|
37
37
|
const DEFAULT_LAYOUT = withSharedValue<FocusedInputLayoutChangedEvent | null>(
|
|
38
|
-
null
|
|
38
|
+
null,
|
|
39
39
|
);
|
|
40
40
|
const defaultContext: KeyboardAnimationContext = {
|
|
41
41
|
enabled: true,
|
|
@@ -58,7 +58,7 @@ export const useKeyboardContext = () => {
|
|
|
58
58
|
|
|
59
59
|
if (__DEV__ && context === defaultContext) {
|
|
60
60
|
console.warn(
|
|
61
|
-
"Couldn't find real values for `KeyboardContext`. Please make sure you're inside of `KeyboardProvider` - otherwise functionality of `react-native-keyboard-controller` will not work."
|
|
61
|
+
"Couldn't find real values for `KeyboardContext`. Please make sure you're inside of `KeyboardProvider` - otherwise functionality of `react-native-keyboard-controller` will not work.",
|
|
62
62
|
);
|
|
63
63
|
}
|
|
64
64
|
|
package/src/hooks.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { useEffect } from
|
|
1
|
+
import { useEffect } from "react";
|
|
2
2
|
|
|
3
|
-
import { KeyboardController } from
|
|
4
|
-
import { AndroidSoftInputModes } from
|
|
5
|
-
import { useKeyboardContext } from
|
|
6
|
-
import { uuid } from
|
|
3
|
+
import { KeyboardController } from "./bindings";
|
|
4
|
+
import { AndroidSoftInputModes } from "./constants";
|
|
5
|
+
import { useKeyboardContext } from "./context";
|
|
6
|
+
import { uuid } from "./utils";
|
|
7
7
|
|
|
8
|
-
import type { AnimatedContext, ReanimatedContext } from
|
|
9
|
-
import type { FocusedInputHandler, KeyboardHandler } from
|
|
10
|
-
import type { DependencyList } from
|
|
8
|
+
import type { AnimatedContext, ReanimatedContext } from "./context";
|
|
9
|
+
import type { FocusedInputHandler, KeyboardHandler } from "./types";
|
|
10
|
+
import type { DependencyList } from "react";
|
|
11
11
|
|
|
12
12
|
export const useResizeMode = () => {
|
|
13
13
|
useEffect(() => {
|
|
14
14
|
KeyboardController.setInputMode(
|
|
15
|
-
AndroidSoftInputModes.SOFT_INPUT_ADJUST_RESIZE
|
|
15
|
+
AndroidSoftInputModes.SOFT_INPUT_ADJUST_RESIZE,
|
|
16
16
|
);
|
|
17
17
|
|
|
18
18
|
return () => KeyboardController.setDefaultMode();
|
|
@@ -35,7 +35,7 @@ export const useReanimatedKeyboardAnimation = (): ReanimatedContext => {
|
|
|
35
35
|
|
|
36
36
|
export function useGenericKeyboardHandler(
|
|
37
37
|
handler: KeyboardHandler,
|
|
38
|
-
deps?: DependencyList
|
|
38
|
+
deps?: DependencyList,
|
|
39
39
|
) {
|
|
40
40
|
const context = useKeyboardContext();
|
|
41
41
|
|
|
@@ -52,7 +52,7 @@ export function useGenericKeyboardHandler(
|
|
|
52
52
|
|
|
53
53
|
export function useKeyboardHandler(
|
|
54
54
|
handler: KeyboardHandler,
|
|
55
|
-
deps?: DependencyList
|
|
55
|
+
deps?: DependencyList,
|
|
56
56
|
) {
|
|
57
57
|
useResizeMode();
|
|
58
58
|
useGenericKeyboardHandler(handler, deps);
|
|
@@ -72,7 +72,7 @@ export function useReanimatedFocusedInput() {
|
|
|
72
72
|
|
|
73
73
|
export function useFocusedInputHandler(
|
|
74
74
|
handler?: FocusedInputHandler,
|
|
75
|
-
deps?: DependencyList
|
|
75
|
+
deps?: DependencyList,
|
|
76
76
|
) {
|
|
77
77
|
const context = useKeyboardContext();
|
|
78
78
|
|