react-native-keyboard-controller 1.19.6 → 1.20.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/KeyboardControllerViewManager.kt +18 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +1 -1
- package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +7 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +2 -2
- package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +16 -0
- package/ios/KeyboardControllerModule.mm +1 -0
- package/ios/observers/FocusedInputObserver.swift +1 -1
- package/ios/views/KeyboardControllerView.mm +11 -0
- package/ios/views/KeyboardControllerViewManager.mm +3 -0
- package/ios/views/KeyboardControllerViewManager.swift +13 -1
- package/lib/commonjs/animated.js +14 -5
- package/lib/commonjs/animated.js.map +1 -1
- package/lib/commonjs/bindings.js +4 -1
- package/lib/commonjs/bindings.js.map +1 -1
- package/lib/commonjs/bindings.native.js +4 -2
- package/lib/commonjs/bindings.native.js.map +1 -1
- package/lib/commonjs/compat.js +65 -0
- package/lib/commonjs/compat.js.map +1 -0
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js +25 -7
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/context.js +1 -0
- package/lib/commonjs/context.js.map +1 -1
- package/lib/commonjs/hooks/index.js +43 -3
- package/lib/commonjs/hooks/index.js.map +1 -1
- package/lib/commonjs/hooks/useKeyboardState/index.js.map +1 -1
- package/lib/commonjs/index.js +12 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/internal.js +16 -16
- package/lib/commonjs/internal.js.map +1 -1
- package/lib/commonjs/specs/KeyboardControllerViewNativeComponent.js +5 -1
- package/lib/commonjs/specs/KeyboardControllerViewNativeComponent.js.map +1 -1
- package/lib/commonjs/types/internal.js.map +1 -1
- package/lib/commonjs/types/module.js.map +1 -1
- package/lib/module/animated.js +16 -7
- package/lib/module/animated.js.map +1 -1
- package/lib/module/bindings.js +3 -0
- package/lib/module/bindings.js.map +1 -1
- package/lib/module/bindings.native.js +3 -1
- package/lib/module/bindings.native.js.map +1 -1
- package/lib/module/compat.js +58 -0
- package/lib/module/compat.js.map +1 -0
- package/lib/module/components/KeyboardAwareScrollView/index.js +26 -8
- package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/context.js +1 -0
- package/lib/module/context.js.map +1 -1
- package/lib/module/hooks/index.js +43 -3
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/hooks/useKeyboardState/index.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal.js +16 -16
- package/lib/module/internal.js.map +1 -1
- package/lib/module/specs/KeyboardControllerViewNativeComponent.js +4 -0
- package/lib/module/specs/KeyboardControllerViewNativeComponent.js.map +1 -1
- package/lib/module/types/internal.js.map +1 -1
- package/lib/module/types/module.js.map +1 -1
- package/lib/typescript/bindings.d.ts +3 -0
- package/lib/typescript/bindings.native.d.ts +1 -0
- package/lib/typescript/compat.d.ts +27 -0
- package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +4 -1
- package/lib/typescript/components/index.d.ts +1 -1
- package/lib/typescript/context.d.ts +6 -4
- package/lib/typescript/hooks/index.d.ts +4 -4
- package/lib/typescript/hooks/useKeyboardState/index.d.ts +3 -3
- package/lib/typescript/index.d.ts +2 -1
- package/lib/typescript/internal.d.ts +2 -3
- package/lib/typescript/specs/KeyboardControllerViewNativeComponent.d.ts +4 -0
- package/lib/typescript/types/internal.d.ts +1 -1
- package/lib/typescript/types/module.d.ts +3 -2
- package/package.json +1 -1
- package/src/animated.tsx +32 -15
- package/src/bindings.native.ts +4 -1
- package/src/bindings.ts +5 -0
- package/src/compat.ts +61 -0
- package/src/components/KeyboardAwareScrollView/index.tsx +43 -11
- package/src/components/index.ts +4 -1
- package/src/context.ts +14 -8
- package/src/hooks/index.ts +68 -11
- package/src/hooks/useKeyboardState/index.ts +4 -4
- package/src/index.ts +2 -0
- package/src/internal.ts +33 -30
- package/src/specs/KeyboardControllerViewNativeComponent.ts +11 -0
- package/src/types/internal.ts +3 -1
- package/src/types/module.ts +3 -2
- package/lib/commonjs/event-handler.d.js +0 -6
- package/lib/commonjs/event-handler.d.js.map +0 -1
- package/lib/commonjs/event-handler.js +0 -19
- package/lib/commonjs/event-handler.js.map +0 -1
- package/lib/commonjs/event-handler.web.js +0 -10
- package/lib/commonjs/event-handler.web.js.map +0 -1
- package/lib/commonjs/event-mappings.js +0 -9
- package/lib/commonjs/event-mappings.js.map +0 -1
- package/lib/module/event-handler.d.js +0 -2
- package/lib/module/event-handler.d.js.map +0 -1
- package/lib/module/event-handler.js +0 -14
- package/lib/module/event-handler.js.map +0 -1
- package/lib/module/event-handler.web.js +0 -5
- package/lib/module/event-handler.web.js.map +0 -1
- package/lib/module/event-mappings.js +0 -3
- package/lib/module/event-mappings.js.map +0 -1
- package/lib/typescript/event-mappings.d.ts +0 -2
- package/src/event-handler.d.ts +0 -8
- package/src/event-handler.js +0 -15
- package/src/event-handler.web.js +0 -5
- package/src/event-mappings.ts +0 -14
package/src/animated.tsx
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/* eslint react/jsx-sort-props: off */
|
|
2
|
-
import React, {
|
|
2
|
+
import React, {
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from "react";
|
|
3
9
|
import { Animated, Platform, StyleSheet } from "react-native";
|
|
4
10
|
import {
|
|
5
11
|
controlEdgeToEdgeValues,
|
|
@@ -7,9 +13,12 @@ import {
|
|
|
7
13
|
} from "react-native-is-edge-to-edge";
|
|
8
14
|
import Reanimated, { useSharedValue } from "react-native-reanimated";
|
|
9
15
|
|
|
10
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
FocusedInputEvents,
|
|
18
|
+
KeyboardControllerView,
|
|
19
|
+
KeyboardControllerViewCommands,
|
|
20
|
+
} from "./bindings";
|
|
11
21
|
import { KeyboardContext } from "./context";
|
|
12
|
-
import { focusedInputEventsMap, keyboardEventsMap } from "./event-mappings";
|
|
13
22
|
import { useAnimatedValue, useEventHandlerRegistration } from "./internal";
|
|
14
23
|
import { KeyboardController } from "./module";
|
|
15
24
|
import {
|
|
@@ -19,10 +28,8 @@ import {
|
|
|
19
28
|
|
|
20
29
|
import type { KeyboardAnimationContext } from "./context";
|
|
21
30
|
import type {
|
|
22
|
-
FocusedInputHandler,
|
|
23
31
|
FocusedInputLayoutChangedEvent,
|
|
24
32
|
KeyboardControllerProps,
|
|
25
|
-
KeyboardHandler,
|
|
26
33
|
NativeEvent,
|
|
27
34
|
} from "./types";
|
|
28
35
|
import type { ViewStyle } from "react-native";
|
|
@@ -120,7 +127,7 @@ export const KeyboardProvider = (props: KeyboardProviderProps) => {
|
|
|
120
127
|
preload = true,
|
|
121
128
|
} = props;
|
|
122
129
|
// ref
|
|
123
|
-
const
|
|
130
|
+
const viewRef = useRef<React.Component<KeyboardControllerProps>>(null);
|
|
124
131
|
// state
|
|
125
132
|
const [enabled, setEnabled] = useState(initiallyEnabled);
|
|
126
133
|
// animated values
|
|
@@ -130,14 +137,23 @@ export const KeyboardProvider = (props: KeyboardProviderProps) => {
|
|
|
130
137
|
const progressSV = useSharedValue(0);
|
|
131
138
|
const heightSV = useSharedValue(0);
|
|
132
139
|
const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);
|
|
133
|
-
const setKeyboardHandlers = useEventHandlerRegistration
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
const setKeyboardHandlers = useEventHandlerRegistration(viewRef);
|
|
141
|
+
const setInputHandlers = useEventHandlerRegistration(viewRef);
|
|
142
|
+
const update = useCallback(async () => {
|
|
143
|
+
KeyboardControllerViewCommands.synchronizeFocusedInputLayout(
|
|
144
|
+
viewRef.current,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
await new Promise((resolve) => {
|
|
148
|
+
const subscription = FocusedInputEvents.addListener(
|
|
149
|
+
"layoutDidSynchronize",
|
|
150
|
+
() => {
|
|
151
|
+
subscription.remove();
|
|
152
|
+
resolve(null);
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
}, []);
|
|
141
157
|
// memo
|
|
142
158
|
const context = useMemo<KeyboardAnimationContext>(
|
|
143
159
|
() => ({
|
|
@@ -145,6 +161,7 @@ export const KeyboardProvider = (props: KeyboardProviderProps) => {
|
|
|
145
161
|
animated: { progress: progress, height: Animated.multiply(height, -1) },
|
|
146
162
|
reanimated: { progress: progressSV, height: heightSV },
|
|
147
163
|
layout,
|
|
164
|
+
update,
|
|
148
165
|
setKeyboardHandlers,
|
|
149
166
|
setInputHandlers,
|
|
150
167
|
setEnabled,
|
|
@@ -241,7 +258,7 @@ export const KeyboardProvider = (props: KeyboardProviderProps) => {
|
|
|
241
258
|
return (
|
|
242
259
|
<KeyboardContext.Provider value={context}>
|
|
243
260
|
<KeyboardControllerViewAnimated
|
|
244
|
-
ref={
|
|
261
|
+
ref={viewRef}
|
|
245
262
|
enabled={enabled}
|
|
246
263
|
navigationBarTranslucent={IS_EDGE_TO_EDGE || navigationBarTranslucent}
|
|
247
264
|
statusBarTranslucent={IS_EDGE_TO_EDGE || statusBarTranslucent}
|
package/src/bindings.native.ts
CHANGED
|
@@ -18,6 +18,7 @@ const LINKING_ERROR =
|
|
|
18
18
|
"- You rebuilt the app after installing the package\n" +
|
|
19
19
|
"- You are not using Expo Go\n";
|
|
20
20
|
|
|
21
|
+
const KeyboardControllerViewNativeComponentModule = require("./specs/KeyboardControllerViewNativeComponent");
|
|
21
22
|
const RCTKeyboardController =
|
|
22
23
|
require("./specs/NativeKeyboardController").default;
|
|
23
24
|
|
|
@@ -55,7 +56,9 @@ export const WindowDimensionsEvents: WindowDimensionsEventsModule = {
|
|
|
55
56
|
eventEmitter.addListener(KEYBOARD_CONTROLLER_NAMESPACE + name, cb),
|
|
56
57
|
};
|
|
57
58
|
export const KeyboardControllerView: React.FC<KeyboardControllerProps> =
|
|
58
|
-
|
|
59
|
+
KeyboardControllerViewNativeComponentModule.default;
|
|
60
|
+
export const KeyboardControllerViewCommands =
|
|
61
|
+
KeyboardControllerViewNativeComponentModule.Commands;
|
|
59
62
|
export const KeyboardGestureArea: React.FC<KeyboardGestureAreaProps> =
|
|
60
63
|
(Platform.OS === "android" && Platform.Version >= 30) || Platform.OS === "ios"
|
|
61
64
|
? require("./specs/KeyboardGestureAreaNativeComponent").default
|
package/src/bindings.ts
CHANGED
|
@@ -53,6 +53,11 @@ export const WindowDimensionsEvents: WindowDimensionsEventsModule = {
|
|
|
53
53
|
*/
|
|
54
54
|
export const KeyboardControllerView =
|
|
55
55
|
View as unknown as React.FC<KeyboardControllerProps>;
|
|
56
|
+
export const KeyboardControllerViewCommands = {
|
|
57
|
+
synchronizeFocusedInputLayout: (
|
|
58
|
+
_ref: React.Component<KeyboardControllerProps> | null,
|
|
59
|
+
) => {},
|
|
60
|
+
};
|
|
56
61
|
/**
|
|
57
62
|
* A view that defines a region on the screen, where gestures will control the keyboard position.
|
|
58
63
|
*
|
package/src/compat.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useSharedValue } from "react-native-reanimated";
|
|
2
|
+
|
|
3
|
+
import { useKeyboardHandler } from "./hooks";
|
|
4
|
+
|
|
5
|
+
export const KeyboardState = {
|
|
6
|
+
UNKNOWN: 0,
|
|
7
|
+
OPENING: 1,
|
|
8
|
+
OPEN: 2,
|
|
9
|
+
CLOSING: 3,
|
|
10
|
+
CLOSED: 4,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A compatibility layer for migration from https://docs.swmansion.com/react-native-reanimated/docs/device/useAnimatedKeyboard.
|
|
15
|
+
*
|
|
16
|
+
* @returns An object containing `height` and `state` properties represented as `SharedValue<number>`.
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { useAnimatedKeyboard, useAnimatedStyle } from 'react-native-keyboard-controller';
|
|
20
|
+
*
|
|
21
|
+
* export default function App() {
|
|
22
|
+
* const keyboard = useAnimatedKeyboard();
|
|
23
|
+
*
|
|
24
|
+
* const animatedStyles = useAnimatedStyle(() => ({
|
|
25
|
+
* transform: [{ translateY: -keyboard.height.value }],
|
|
26
|
+
* }));
|
|
27
|
+
* }
|
|
28
|
+
*/
|
|
29
|
+
export const useAnimatedKeyboard = () => {
|
|
30
|
+
const height = useSharedValue(0);
|
|
31
|
+
const state = useSharedValue(KeyboardState.UNKNOWN);
|
|
32
|
+
|
|
33
|
+
useKeyboardHandler(
|
|
34
|
+
{
|
|
35
|
+
onStart: (e) => {
|
|
36
|
+
"worklet";
|
|
37
|
+
|
|
38
|
+
state.set(e.height > 0 ? KeyboardState.OPENING : KeyboardState.CLOSING);
|
|
39
|
+
},
|
|
40
|
+
onMove: (e) => {
|
|
41
|
+
"worklet";
|
|
42
|
+
|
|
43
|
+
height.set(e.height);
|
|
44
|
+
},
|
|
45
|
+
onInteractive: (e) => {
|
|
46
|
+
"worklet";
|
|
47
|
+
|
|
48
|
+
height.set(e.height);
|
|
49
|
+
},
|
|
50
|
+
onEnd: (e) => {
|
|
51
|
+
"worklet";
|
|
52
|
+
|
|
53
|
+
state.set(e.height > 0 ? KeyboardState.OPEN : KeyboardState.CLOSED);
|
|
54
|
+
height.set(e.height);
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
[],
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return { height, state };
|
|
61
|
+
};
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useMemo,
|
|
7
|
+
} from "react";
|
|
2
8
|
import Reanimated, {
|
|
3
9
|
clamp,
|
|
4
10
|
interpolate,
|
|
@@ -44,6 +50,9 @@ export type KeyboardAwareScrollViewProps = {
|
|
|
44
50
|
/** Custom component for `ScrollView`. Default is `ScrollView`. */
|
|
45
51
|
ScrollViewComponent?: React.ComponentType<ScrollViewProps>;
|
|
46
52
|
} & ScrollViewProps;
|
|
53
|
+
export type KeyboardAwareScrollViewRef = {
|
|
54
|
+
assureFocusedInputVisible: () => void;
|
|
55
|
+
} & ScrollView;
|
|
47
56
|
|
|
48
57
|
// Everything begins from `onStart` handler. This handler is called every time,
|
|
49
58
|
// when keyboard changes its size or when focused `TextInput` was changed. In
|
|
@@ -99,7 +108,7 @@ export type KeyboardAwareScrollViewProps = {
|
|
|
99
108
|
* ```
|
|
100
109
|
*/
|
|
101
110
|
const KeyboardAwareScrollView = forwardRef<
|
|
102
|
-
|
|
111
|
+
KeyboardAwareScrollViewRef,
|
|
103
112
|
React.PropsWithChildren<KeyboardAwareScrollViewProps>
|
|
104
113
|
>(
|
|
105
114
|
(
|
|
@@ -117,6 +126,7 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
117
126
|
ref,
|
|
118
127
|
) => {
|
|
119
128
|
const scrollViewAnimatedRef = useAnimatedRef<Reanimated.ScrollView>();
|
|
129
|
+
const scrollViewRef = React.useRef<ScrollView>(null);
|
|
120
130
|
const scrollViewTarget = useSharedValue<number | null>(null);
|
|
121
131
|
const scrollPosition = useSharedValue(0);
|
|
122
132
|
const position = useScrollViewOffset(scrollViewAnimatedRef);
|
|
@@ -126,7 +136,7 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
126
136
|
const tag = useSharedValue(-1);
|
|
127
137
|
const initialKeyboardSize = useSharedValue(0);
|
|
128
138
|
const scrollBeforeKeyboardMovement = useSharedValue(0);
|
|
129
|
-
const { input } = useReanimatedFocusedInput();
|
|
139
|
+
const { input, update } = useReanimatedFocusedInput();
|
|
130
140
|
const layout = useSharedValue<FocusedInputLayoutChangedEvent | null>(null);
|
|
131
141
|
const lastSelection =
|
|
132
142
|
useSharedValue<FocusedInputSelectionChangedEvent | null>(null);
|
|
@@ -134,11 +144,7 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
134
144
|
const { height } = useWindowDimensions();
|
|
135
145
|
|
|
136
146
|
const onRef = useCallback((assignedRef: Reanimated.ScrollView) => {
|
|
137
|
-
|
|
138
|
-
ref(assignedRef);
|
|
139
|
-
} else if (ref) {
|
|
140
|
-
ref.current = assignedRef;
|
|
141
|
-
}
|
|
147
|
+
scrollViewRef.current = assignedRef;
|
|
142
148
|
|
|
143
149
|
scrollViewAnimatedRef(assignedRef);
|
|
144
150
|
}, []);
|
|
@@ -392,10 +398,36 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
392
398
|
[maybeScroll, disableScrollOnKeyboardHide, syncKeyboardFrame],
|
|
393
399
|
);
|
|
394
400
|
|
|
401
|
+
const synchronize = useCallback(async () => {
|
|
402
|
+
await update();
|
|
403
|
+
|
|
404
|
+
runOnUI(() => {
|
|
405
|
+
"worklet";
|
|
406
|
+
|
|
407
|
+
scrollFromCurrentPosition();
|
|
408
|
+
})();
|
|
409
|
+
}, [update, scrollFromCurrentPosition]);
|
|
410
|
+
|
|
411
|
+
useImperativeHandle(
|
|
412
|
+
ref,
|
|
413
|
+
() => {
|
|
414
|
+
const scrollView = scrollViewRef.current;
|
|
415
|
+
|
|
416
|
+
const existingMethods = scrollView ? { ...scrollView } : {};
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
...existingMethods,
|
|
420
|
+
|
|
421
|
+
assureFocusedInputVisible: () => {
|
|
422
|
+
synchronize();
|
|
423
|
+
},
|
|
424
|
+
} as KeyboardAwareScrollViewRef;
|
|
425
|
+
},
|
|
426
|
+
[synchronize],
|
|
427
|
+
);
|
|
428
|
+
|
|
395
429
|
useEffect(() => {
|
|
396
|
-
|
|
397
|
-
scrollBeforeKeyboardMovement.value,
|
|
398
|
-
);
|
|
430
|
+
synchronize();
|
|
399
431
|
}, [bottomOffset]);
|
|
400
432
|
|
|
401
433
|
useAnimatedReaction(
|
package/src/components/index.ts
CHANGED
|
@@ -7,5 +7,8 @@ export {
|
|
|
7
7
|
} from "./KeyboardToolbar";
|
|
8
8
|
export type { KeyboardAvoidingViewProps } from "./KeyboardAvoidingView";
|
|
9
9
|
export type { KeyboardStickyViewProps } from "./KeyboardStickyView";
|
|
10
|
-
export type {
|
|
10
|
+
export type {
|
|
11
|
+
KeyboardAwareScrollViewProps,
|
|
12
|
+
KeyboardAwareScrollViewRef,
|
|
13
|
+
} from "./KeyboardAwareScrollView";
|
|
11
14
|
export type { KeyboardToolbarProps } from "./KeyboardToolbar";
|
package/src/context.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { createContext, useContext } from "react";
|
|
2
2
|
import { Animated } from "react-native";
|
|
3
3
|
|
|
4
|
-
import type {
|
|
5
|
-
FocusedInputHandler,
|
|
6
|
-
FocusedInputLayoutChangedEvent,
|
|
7
|
-
KeyboardHandler,
|
|
8
|
-
} from "./types";
|
|
4
|
+
import type { FocusedInputLayoutChangedEvent } from "./types";
|
|
9
5
|
import type React from "react";
|
|
10
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
EventHandlerProcessed,
|
|
8
|
+
SharedValue,
|
|
9
|
+
} from "react-native-reanimated";
|
|
11
10
|
|
|
12
11
|
export type AnimatedContext = {
|
|
13
12
|
/**
|
|
@@ -36,10 +35,16 @@ export type KeyboardAnimationContext = {
|
|
|
36
35
|
reanimated: ReanimatedContext;
|
|
37
36
|
/** Layout of the focused `TextInput` represented as `SharedValue`. */
|
|
38
37
|
layout: SharedValue<FocusedInputLayoutChangedEvent | null>;
|
|
38
|
+
/** Method for updating info about focused input layout. */
|
|
39
|
+
update: () => Promise<void>;
|
|
39
40
|
/** Method for setting workletized keyboard handlers. */
|
|
40
|
-
setKeyboardHandlers: (
|
|
41
|
+
setKeyboardHandlers: (
|
|
42
|
+
handlers: EventHandlerProcessed<never, never>,
|
|
43
|
+
) => () => void;
|
|
41
44
|
/** Method for setting workletized handlers for tracking focused input events. */
|
|
42
|
-
setInputHandlers: (
|
|
45
|
+
setInputHandlers: (
|
|
46
|
+
handlers: EventHandlerProcessed<never, never>,
|
|
47
|
+
) => () => void;
|
|
43
48
|
/** Method to enable/disable KeyboardController library. */
|
|
44
49
|
setEnabled: React.Dispatch<React.SetStateAction<boolean>>;
|
|
45
50
|
};
|
|
@@ -68,6 +73,7 @@ const defaultContext: KeyboardAnimationContext = {
|
|
|
68
73
|
height: DEFAULT_SHARED_VALUE,
|
|
69
74
|
},
|
|
70
75
|
layout: DEFAULT_LAYOUT,
|
|
76
|
+
update: Promise.resolve,
|
|
71
77
|
setKeyboardHandlers: NESTED_NOOP,
|
|
72
78
|
setInputHandlers: NESTED_NOOP,
|
|
73
79
|
setEnabled: NOOP,
|
package/src/hooks/index.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { useEffect, useLayoutEffect } from "react";
|
|
2
|
+
import { useEvent, useHandler } from "react-native-reanimated";
|
|
2
3
|
|
|
3
4
|
import { AndroidSoftInputModes } from "../constants";
|
|
4
5
|
import { useKeyboardContext } from "../context";
|
|
5
6
|
import { KeyboardController } from "../module";
|
|
6
7
|
|
|
7
8
|
import type { AnimatedContext, ReanimatedContext } from "../context";
|
|
8
|
-
import type {
|
|
9
|
-
|
|
9
|
+
import type {
|
|
10
|
+
FocusedInputHandler,
|
|
11
|
+
FocusedInputSelectionChangedEvent,
|
|
12
|
+
FocusedInputTextChangedEvent,
|
|
13
|
+
KeyboardHandler,
|
|
14
|
+
NativeEvent,
|
|
15
|
+
} from "../types";
|
|
10
16
|
|
|
11
17
|
/**
|
|
12
18
|
* Hook that sets the Android soft input mode to adjust resize on mount and
|
|
@@ -107,12 +113,43 @@ export const useReanimatedKeyboardAnimation = (): ReanimatedContext => {
|
|
|
107
113
|
*/
|
|
108
114
|
export function useGenericKeyboardHandler(
|
|
109
115
|
handler: KeyboardHandler,
|
|
110
|
-
deps?:
|
|
116
|
+
deps?: unknown[],
|
|
111
117
|
) {
|
|
112
118
|
const context = useKeyboardContext();
|
|
113
119
|
|
|
120
|
+
const { doDependenciesDiffer } = useHandler(handler, deps);
|
|
121
|
+
|
|
122
|
+
const eventHandler = useEvent<NativeEvent>(
|
|
123
|
+
(event) => {
|
|
124
|
+
"worklet";
|
|
125
|
+
|
|
126
|
+
if (event.eventName.endsWith("onKeyboardMoveStart")) {
|
|
127
|
+
handler.onStart?.(event);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (event.eventName.endsWith("onKeyboardMove")) {
|
|
131
|
+
handler.onMove?.(event);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (event.eventName.endsWith("onKeyboardMoveEnd")) {
|
|
135
|
+
handler.onEnd?.(event);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (event.eventName.endsWith("onKeyboardMoveInteractive")) {
|
|
139
|
+
handler.onInteractive?.(event);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
[
|
|
143
|
+
"onKeyboardMoveStart",
|
|
144
|
+
"onKeyboardMove",
|
|
145
|
+
"onKeyboardMoveEnd",
|
|
146
|
+
"onKeyboardMoveInteractive",
|
|
147
|
+
],
|
|
148
|
+
doDependenciesDiffer,
|
|
149
|
+
);
|
|
150
|
+
|
|
114
151
|
useLayoutEffect(() => {
|
|
115
|
-
const cleanup = context.setKeyboardHandlers(
|
|
152
|
+
const cleanup = context.setKeyboardHandlers(eventHandler);
|
|
116
153
|
|
|
117
154
|
return () => cleanup();
|
|
118
155
|
}, deps);
|
|
@@ -149,10 +186,7 @@ export function useGenericKeyboardHandler(
|
|
|
149
186
|
* }
|
|
150
187
|
* ```
|
|
151
188
|
*/
|
|
152
|
-
export function useKeyboardHandler(
|
|
153
|
-
handler: KeyboardHandler,
|
|
154
|
-
deps?: DependencyList,
|
|
155
|
-
) {
|
|
189
|
+
export function useKeyboardHandler(handler: KeyboardHandler, deps?: unknown[]) {
|
|
156
190
|
useResizeMode();
|
|
157
191
|
useGenericKeyboardHandler(handler, deps);
|
|
158
192
|
}
|
|
@@ -202,7 +236,10 @@ export function useKeyboardController() {
|
|
|
202
236
|
export function useReanimatedFocusedInput() {
|
|
203
237
|
const context = useKeyboardContext();
|
|
204
238
|
|
|
205
|
-
return {
|
|
239
|
+
return {
|
|
240
|
+
input: context.layout,
|
|
241
|
+
update: context.update,
|
|
242
|
+
};
|
|
206
243
|
}
|
|
207
244
|
|
|
208
245
|
/**
|
|
@@ -224,12 +261,32 @@ export function useReanimatedFocusedInput() {
|
|
|
224
261
|
*/
|
|
225
262
|
export function useFocusedInputHandler(
|
|
226
263
|
handler: FocusedInputHandler,
|
|
227
|
-
deps?:
|
|
264
|
+
deps?: unknown[],
|
|
228
265
|
) {
|
|
229
266
|
const context = useKeyboardContext();
|
|
230
267
|
|
|
268
|
+
const { doDependenciesDiffer } = useHandler<never, never>(handler, deps);
|
|
269
|
+
|
|
270
|
+
const eventHandler = useEvent<
|
|
271
|
+
FocusedInputSelectionChangedEvent | FocusedInputTextChangedEvent
|
|
272
|
+
>(
|
|
273
|
+
(event) => {
|
|
274
|
+
"worklet";
|
|
275
|
+
|
|
276
|
+
if (event.eventName.endsWith("onFocusedInputTextChanged")) {
|
|
277
|
+
handler.onChangeText?.(event as FocusedInputTextChangedEvent);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (event.eventName.endsWith("onFocusedInputSelectionChanged")) {
|
|
281
|
+
handler.onSelectionChange?.(event as FocusedInputSelectionChangedEvent);
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
["onFocusedInputTextChanged", "onFocusedInputSelectionChanged"],
|
|
285
|
+
doDependenciesDiffer,
|
|
286
|
+
);
|
|
287
|
+
|
|
231
288
|
useLayoutEffect(() => {
|
|
232
|
-
const cleanup = context.setInputHandlers(
|
|
289
|
+
const cleanup = context.setInputHandlers(eventHandler);
|
|
233
290
|
|
|
234
291
|
return () => cleanup();
|
|
235
292
|
}, deps);
|
|
@@ -3,7 +3,7 @@ import { useEffect, useState } from "react";
|
|
|
3
3
|
import { KeyboardEvents } from "../../bindings";
|
|
4
4
|
import { KeyboardController } from "../../module";
|
|
5
5
|
|
|
6
|
-
import type {
|
|
6
|
+
import type { IKeyboardState } from "../../types";
|
|
7
7
|
|
|
8
8
|
const EVENTS = ["keyboardDidShow", "keyboardDidHide"] as const;
|
|
9
9
|
|
|
@@ -12,9 +12,9 @@ const getLatestState = () => ({
|
|
|
12
12
|
isVisible: KeyboardController.isVisible(),
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
type KeyboardStateSelector<T> = (state:
|
|
15
|
+
type KeyboardStateSelector<T> = (state: IKeyboardState) => T;
|
|
16
16
|
|
|
17
|
-
const defaultSelector: KeyboardStateSelector<
|
|
17
|
+
const defaultSelector: KeyboardStateSelector<IKeyboardState> = (state) => state;
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* React Hook that represents the current keyboard state on iOS and Android.
|
|
@@ -40,7 +40,7 @@ const defaultSelector: KeyboardStateSelector<KeyboardState> = (state) => state;
|
|
|
40
40
|
* }
|
|
41
41
|
* ```
|
|
42
42
|
*/
|
|
43
|
-
function useKeyboardState<T =
|
|
43
|
+
function useKeyboardState<T = IKeyboardState>(
|
|
44
44
|
selector: KeyboardStateSelector<T> = defaultSelector as KeyboardStateSelector<T>,
|
|
45
45
|
): T {
|
|
46
46
|
const [state, setState] = useState<T>(() => selector(getLatestState()));
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from "./hooks";
|
|
|
5
5
|
export * from "./constants";
|
|
6
6
|
export * from "./module";
|
|
7
7
|
export * from "./types";
|
|
8
|
+
export * from "./compat";
|
|
8
9
|
|
|
9
10
|
export {
|
|
10
11
|
KeyboardAvoidingView,
|
|
@@ -18,6 +19,7 @@ export type {
|
|
|
18
19
|
KeyboardAvoidingViewProps,
|
|
19
20
|
KeyboardStickyViewProps,
|
|
20
21
|
KeyboardAwareScrollViewProps,
|
|
22
|
+
KeyboardAwareScrollViewRef,
|
|
21
23
|
KeyboardToolbarProps,
|
|
22
24
|
} from "./components";
|
|
23
25
|
export { OverKeyboardView, KeyboardExtender } from "./views";
|
package/src/internal.ts
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import { useRef } from "react";
|
|
2
2
|
import { Animated } from "react-native";
|
|
3
3
|
|
|
4
|
-
import { registerEventHandler, unregisterEventHandler } from "./event-handler";
|
|
5
4
|
import { findNodeHandle } from "./utils/findNodeHandle";
|
|
6
5
|
|
|
7
|
-
type
|
|
6
|
+
import type { EventHandlerProcessed } from "react-native-reanimated";
|
|
7
|
+
|
|
8
8
|
type ComponentOrHandle = Parameters<typeof findNodeHandle>[0];
|
|
9
9
|
|
|
10
|
+
type WorkletHandler = {
|
|
11
|
+
registerForEvents: (viewTag: number) => void;
|
|
12
|
+
unregisterFromEvents: (viewTag: number) => void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type WorkletHandlerOrWorkletHandlerObject =
|
|
16
|
+
| WorkletHandler
|
|
17
|
+
| {
|
|
18
|
+
workletEventHandler: WorkletHandler;
|
|
19
|
+
};
|
|
20
|
+
|
|
10
21
|
/**
|
|
11
22
|
* An internal hook that helps to register workletized event handlers.
|
|
12
23
|
*
|
|
13
|
-
* @param map - Map of event handlers and their names.
|
|
14
24
|
* @param viewTagRef - Ref to the view that produces events.
|
|
15
25
|
* @returns A function that registers supplied event handlers.
|
|
16
26
|
* @example
|
|
@@ -21,14 +31,12 @@ type ComponentOrHandle = Parameters<typeof findNodeHandle>[0];
|
|
|
21
31
|
* );
|
|
22
32
|
* ```
|
|
23
33
|
*/
|
|
24
|
-
export function useEventHandlerRegistration
|
|
25
|
-
H extends Partial<Record<string, EventHandler>>,
|
|
26
|
-
>(
|
|
27
|
-
map: Map<keyof H, string>,
|
|
34
|
+
export function useEventHandlerRegistration(
|
|
28
35
|
viewTagRef: React.MutableRefObject<ComponentOrHandle>,
|
|
29
36
|
) {
|
|
30
|
-
const onRegisterHandler = (handler:
|
|
31
|
-
const
|
|
37
|
+
const onRegisterHandler = (handler: EventHandlerProcessed<never, never>) => {
|
|
38
|
+
const currentHandler =
|
|
39
|
+
handler as unknown as WorkletHandlerOrWorkletHandlerObject;
|
|
32
40
|
const attachWorkletHandlers = () => {
|
|
33
41
|
const viewTag = findNodeHandle(viewTagRef.current);
|
|
34
42
|
|
|
@@ -38,26 +46,13 @@ export function useEventHandlerRegistration<
|
|
|
38
46
|
);
|
|
39
47
|
}
|
|
40
48
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
(event: Parameters<NonNullable<H[keyof H]>>[0]) => {
|
|
49
|
-
"worklet";
|
|
50
|
-
|
|
51
|
-
functionToCall?.(event);
|
|
52
|
-
},
|
|
53
|
-
eventName,
|
|
54
|
-
viewTag,
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return null;
|
|
59
|
-
}),
|
|
60
|
-
);
|
|
49
|
+
if (viewTag) {
|
|
50
|
+
if ("workletEventHandler" in currentHandler) {
|
|
51
|
+
currentHandler.workletEventHandler.registerForEvents(viewTag);
|
|
52
|
+
} else {
|
|
53
|
+
currentHandler.registerForEvents(viewTag);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
61
56
|
};
|
|
62
57
|
|
|
63
58
|
if (viewTagRef.current) {
|
|
@@ -68,7 +63,15 @@ export function useEventHandlerRegistration<
|
|
|
68
63
|
}
|
|
69
64
|
|
|
70
65
|
return () => {
|
|
71
|
-
|
|
66
|
+
const viewTag = findNodeHandle(viewTagRef.current);
|
|
67
|
+
|
|
68
|
+
if (viewTag) {
|
|
69
|
+
if ("workletEventHandler" in currentHandler) {
|
|
70
|
+
currentHandler.workletEventHandler.unregisterFromEvents(viewTag);
|
|
71
|
+
} else {
|
|
72
|
+
currentHandler.unregisterFromEvents(viewTag);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
72
75
|
};
|
|
73
76
|
};
|
|
74
77
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import codegenNativeCommands from "react-native/Libraries/Utilities/codegenNativeCommands";
|
|
1
2
|
import codegenNativeComponent from "react-native/Libraries/Utilities/codegenNativeComponent";
|
|
2
3
|
|
|
3
4
|
import type { HostComponent } from "react-native";
|
|
@@ -66,6 +67,16 @@ export interface NativeProps extends ViewProps {
|
|
|
66
67
|
onFocusedInputSelectionChanged?: DirectEventHandler<FocusedInputSelectionChangedEvent>;
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
interface NativeCommands {
|
|
71
|
+
synchronizeFocusedInputLayout: (
|
|
72
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>,
|
|
73
|
+
) => void;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
|
|
77
|
+
supportedCommands: ["synchronizeFocusedInputLayout"],
|
|
78
|
+
});
|
|
79
|
+
|
|
69
80
|
export default codegenNativeComponent<NativeProps>("KeyboardControllerView", {
|
|
70
81
|
interfaceOnly: true,
|
|
71
82
|
}) as HostComponent<NativeProps>;
|
package/src/types/internal.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { EmitterSubscription } from "react-native";
|
|
2
2
|
|
|
3
|
-
export type FocusedInputAvailableEvents =
|
|
3
|
+
export type FocusedInputAvailableEvents =
|
|
4
|
+
| "focusDidSet"
|
|
5
|
+
| "layoutDidSynchronize";
|
|
4
6
|
export type FocusedInputEventData = {
|
|
5
7
|
current: number;
|
|
6
8
|
count: number;
|
package/src/types/module.ts
CHANGED
|
@@ -23,7 +23,7 @@ export type KeyboardEventData = {
|
|
|
23
23
|
/**
|
|
24
24
|
* An object that represent current keyboard state.
|
|
25
25
|
*/
|
|
26
|
-
export type
|
|
26
|
+
export type IKeyboardState = {
|
|
27
27
|
/** Whether the keyboard is currently visible. */
|
|
28
28
|
isVisible: boolean;
|
|
29
29
|
} & KeyboardEventData;
|
|
@@ -85,10 +85,11 @@ export type KeyboardControllerModule = {
|
|
|
85
85
|
// all platforms
|
|
86
86
|
/**
|
|
87
87
|
* Dismisses the active keyboard. Removes a focus by default, but allows to pass `{keepFocus: true}` to keep focus.
|
|
88
|
+
* If you want to close keyboard immediately pass `{animated: false}`.
|
|
88
89
|
*
|
|
89
90
|
* @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/keyboard-controller#dismiss|docs} page for more details.
|
|
90
91
|
*/
|
|
91
|
-
dismiss: (options?: DismissOptions) => Promise<void>;
|
|
92
|
+
dismiss: (options?: Partial<DismissOptions>) => Promise<void>;
|
|
92
93
|
/**
|
|
93
94
|
* Moves focus to the specified direction (`next`, `prev` or `current` to restore a focus).
|
|
94
95
|
*
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["event-handler.d.ts"],"sourcesContent":["declare function registerEventHandler(\n handler: (event: never) => void,\n eventName: string,\n viewTag: number,\n): number;\ndeclare function unregisterEventHandler(id: number): void;\n\nexport { registerEventHandler, unregisterEventHandler };\n"],"mappings":"","ignoreList":[]}
|