Skip to content

Commit 41858c7

Browse files
authored
feat: useAnimatedKeyboard compat layer (#1220)
## 📜 Description Added `useAnimatedKeyboard` hook (same as in reanimated, but based on keyboard-controller API). ## 💡 Motivation and Context Based on software-mansion/react-native-reanimated#8622 we want to deliver as smooth as possible way to migrate from a deprecated API. In many cases people don't want to copy/paste code and manage it on their own, so in this PR I'm adding a proposed compat layer directly in the core of `react-native-keyboard-controller`. Using this compat layer devs will just need: - install this lib; - change the import to use new hook; ## 📢 Changelog <!-- High level overview of important changes --> <!-- For example: fixed status bar manipulation; added new types declarations; --> <!-- If your changes don't affect one of platform/language below - then remove this platform/language --> ### JS - added `useAnimatedKeyboard`/`KeyboardState` - renamed `KeyboardState` to `IKeyboardState` since it conflicts with reanimated name; ## 🤔 How Has This Been Tested? Tested via e2e tests that I didn't break anything accidentally. ## 📸 Screenshots (if appropriate): <img width="633" height="311" alt="image" src="https://github.com/user-attachments/assets/9b3039d6-d59e-4f14-96ff-d8fee0b12447" /> ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
1 parent d4977fc commit 41858c7

File tree

4 files changed

+67
-5
lines changed

4 files changed

+67
-5
lines changed

src/compat.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
};

src/hooks/useKeyboardState/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useEffect, useState } from "react";
33
import { KeyboardEvents } from "../../bindings";
44
import { KeyboardController } from "../../module";
55

6-
import type { KeyboardState } from "../../types";
6+
import type { IKeyboardState } from "../../types";
77

88
const EVENTS = ["keyboardDidShow", "keyboardDidHide"] as const;
99

@@ -12,9 +12,9 @@ const getLatestState = () => ({
1212
isVisible: KeyboardController.isVisible(),
1313
});
1414

15-
type KeyboardStateSelector<T> = (state: KeyboardState) => T;
15+
type KeyboardStateSelector<T> = (state: IKeyboardState) => T;
1616

17-
const defaultSelector: KeyboardStateSelector<KeyboardState> = (state) => state;
17+
const defaultSelector: KeyboardStateSelector<IKeyboardState> = (state) => state;
1818

1919
/**
2020
* React Hook that represents the current keyboard state on iOS and Android.
@@ -40,7 +40,7 @@ const defaultSelector: KeyboardStateSelector<KeyboardState> = (state) => state;
4040
* }
4141
* ```
4242
*/
43-
function useKeyboardState<T = KeyboardState>(
43+
function useKeyboardState<T = IKeyboardState>(
4444
selector: KeyboardStateSelector<T> = defaultSelector as KeyboardStateSelector<T>,
4545
): T {
4646
const [state, setState] = useState<T>(() => selector(getLatestState()));

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export * from "./hooks";
55
export * from "./constants";
66
export * from "./module";
77
export * from "./types";
8+
export * from "./compat";
89

910
export {
1011
KeyboardAvoidingView,

src/types/module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export type KeyboardEventData = {
2323
/**
2424
* An object that represent current keyboard state.
2525
*/
26-
export type KeyboardState = {
26+
export type IKeyboardState = {
2727
/** Whether the keyboard is currently visible. */
2828
isVisible: boolean;
2929
} & KeyboardEventData;

0 commit comments

Comments
 (0)