react-native-keyboard-controller 1.7.0 → 1.8.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/README.md +1 -0
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +5 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +4 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +111 -49
- package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +5 -0
- package/ios/KeyboardControllerView.mm +16 -1
- package/ios/KeyboardControllerViewManager.mm +4 -0
- package/ios/KeyboardControllerViewManager.swift +11 -1
- package/lib/commonjs/animated.js +17 -3
- package/lib/commonjs/animated.js.map +1 -1
- package/lib/commonjs/components/KeyboardAvoidingView/hooks.js +9 -1
- package/lib/commonjs/components/KeyboardAvoidingView/hooks.js.map +1 -1
- package/lib/commonjs/components/KeyboardAvoidingView/index.js +7 -4
- package/lib/commonjs/components/KeyboardAvoidingView/index.js.map +1 -1
- package/lib/commonjs/context.js +3 -1
- package/lib/commonjs/context.js.map +1 -1
- package/lib/commonjs/hooks.js +8 -0
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/commonjs/index.js +0 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/monkey-patch.android.js +32 -20
- package/lib/commonjs/monkey-patch.android.js.map +1 -1
- package/lib/commonjs/monkey-patch.js +11 -1
- package/lib/commonjs/monkey-patch.js.map +1 -1
- package/lib/commonjs/specs/KeyboardControllerViewNativeComponent.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/module/animated.js +18 -4
- package/lib/module/animated.js.map +1 -1
- package/lib/module/components/KeyboardAvoidingView/hooks.js +9 -1
- package/lib/module/components/KeyboardAvoidingView/hooks.js.map +1 -1
- package/lib/module/components/KeyboardAvoidingView/index.js +8 -5
- package/lib/module/components/KeyboardAvoidingView/index.js.map +1 -1
- package/lib/module/context.js +3 -1
- package/lib/module/context.js.map +1 -1
- package/lib/module/hooks.js +7 -0
- package/lib/module/hooks.js.map +1 -1
- package/lib/module/index.js +0 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/monkey-patch.android.js +26 -20
- package/lib/module/monkey-patch.android.js.map +1 -1
- package/lib/module/monkey-patch.js +3 -0
- package/lib/module/monkey-patch.js.map +1 -1
- package/lib/module/specs/KeyboardControllerViewNativeComponent.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/animated.d.ts +8 -1
- package/lib/typescript/components/KeyboardAvoidingView/hooks.d.ts +1 -0
- package/lib/typescript/context.d.ts +4 -2
- package/lib/typescript/hooks.d.ts +4 -0
- package/lib/typescript/index.d.ts +0 -1
- package/lib/typescript/monkey-patch.android.d.ts +2 -1
- package/lib/typescript/monkey-patch.d.ts +2 -0
- package/lib/typescript/specs/KeyboardControllerViewNativeComponent.d.ts +1 -0
- package/lib/typescript/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/animated.tsx +25 -4
- package/src/components/KeyboardAvoidingView/hooks.ts +8 -1
- package/src/components/KeyboardAvoidingView/index.tsx +8 -4
- package/src/context.ts +6 -2
- package/src/hooks.ts +6 -0
- package/src/index.ts +0 -2
- package/src/monkey-patch.android.ts +27 -21
- package/src/monkey-patch.ts +3 -0
- package/src/specs/KeyboardControllerViewNativeComponent.ts +1 -0
- package/src/types.ts +1 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { Animated } from 'react-native';
|
|
3
3
|
import type { SharedValue } from 'react-native-reanimated';
|
|
4
4
|
import type { KeyboardHandlers } from './types';
|
|
@@ -11,9 +11,11 @@ export type ReanimatedContext = {
|
|
|
11
11
|
height: SharedValue<number>;
|
|
12
12
|
};
|
|
13
13
|
export type KeyboardAnimationContext = {
|
|
14
|
+
enabled: boolean;
|
|
14
15
|
animated: AnimatedContext;
|
|
15
16
|
reanimated: ReanimatedContext;
|
|
16
17
|
setHandlers: (handlers: KeyboardHandlers) => void;
|
|
18
|
+
setEnabled: React.Dispatch<React.SetStateAction<boolean>>;
|
|
17
19
|
};
|
|
18
|
-
export declare const KeyboardContext:
|
|
20
|
+
export declare const KeyboardContext: React.Context<KeyboardAnimationContext>;
|
|
19
21
|
export declare const useKeyboardContext: () => KeyboardAnimationContext;
|
|
@@ -6,3 +6,7 @@ export declare const useKeyboardAnimation: () => AnimatedContext;
|
|
|
6
6
|
export declare const useReanimatedKeyboardAnimation: () => ReanimatedContext;
|
|
7
7
|
export declare function useGenericKeyboardHandler(handler: KeyboardHandler, deps?: DependencyList): void;
|
|
8
8
|
export declare function useKeyboardHandler(handler: KeyboardHandler, deps?: DependencyList): void;
|
|
9
|
+
export declare function useKeyboardController(): {
|
|
10
|
+
setEnabled: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare const applyMonkeyPatch: () => void;
|
|
2
|
+
export declare const revertMonkeyPatch: () => void;
|
|
@@ -8,6 +8,7 @@ type KeyboardMoveEvent = Readonly<{
|
|
|
8
8
|
target: Int32;
|
|
9
9
|
}>;
|
|
10
10
|
export interface NativeProps extends ViewProps {
|
|
11
|
+
enabled?: boolean;
|
|
11
12
|
statusBarTranslucent?: boolean;
|
|
12
13
|
navigationBarTranslucent?: boolean;
|
|
13
14
|
onKeyboardMoveStart?: DirectEventHandler<KeyboardMoveEvent>;
|
|
@@ -9,6 +9,7 @@ export type EventWithName<T> = {
|
|
|
9
9
|
eventName: string;
|
|
10
10
|
} & T;
|
|
11
11
|
export type KeyboardControllerProps = {
|
|
12
|
+
enabled?: boolean;
|
|
12
13
|
onKeyboardMoveStart?: (e: NativeSyntheticEvent<EventWithName<NativeEvent>>) => void;
|
|
13
14
|
onKeyboardMove?: (e: NativeSyntheticEvent<EventWithName<NativeEvent>>) => void;
|
|
14
15
|
onKeyboardMoveEnd?: (e: NativeSyntheticEvent<EventWithName<NativeEvent>>) => void;
|
package/package.json
CHANGED
package/src/animated.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import React, { useMemo } from 'react';
|
|
1
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import { Animated, Platform, StyleSheet, ViewStyle } from 'react-native';
|
|
3
3
|
import Reanimated, { useSharedValue } from 'react-native-reanimated';
|
|
4
4
|
|
|
5
|
-
import { KeyboardContext } from './context';
|
|
5
|
+
import { KeyboardAnimationContext, KeyboardContext } from './context';
|
|
6
6
|
import { useSharedHandlers, useAnimatedValue } from './internal';
|
|
7
7
|
import { KeyboardControllerView } from './bindings';
|
|
8
8
|
import { useAnimatedKeyboardHandler } from './reanimated';
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
KeyboardHandler,
|
|
13
13
|
NativeEvent,
|
|
14
14
|
} from './types';
|
|
15
|
+
import { applyMonkeyPatch, revertMonkeyPatch } from './monkey-patch';
|
|
15
16
|
|
|
16
17
|
const KeyboardControllerViewAnimated = Reanimated.createAnimatedComponent(
|
|
17
18
|
Animated.createAnimatedComponent(
|
|
@@ -54,13 +55,22 @@ type KeyboardProviderProps = {
|
|
|
54
55
|
* @platform android
|
|
55
56
|
*/
|
|
56
57
|
navigationBarTranslucent?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* A boolean prop indicating whether the module is enabled. It indicate only initial state,
|
|
60
|
+
* i. e. if you try to change this prop after component mount it will not have any effect.
|
|
61
|
+
* To change the property in runtime use `useKeyboardController` hook and `setEnabled` method.
|
|
62
|
+
* Defaults to `true`.
|
|
63
|
+
*/
|
|
64
|
+
enabled?: boolean;
|
|
57
65
|
};
|
|
58
66
|
|
|
59
67
|
export const KeyboardProvider = ({
|
|
60
68
|
children,
|
|
61
69
|
statusBarTranslucent,
|
|
62
70
|
navigationBarTranslucent,
|
|
71
|
+
enabled: initiallyEnabled = true,
|
|
63
72
|
}: KeyboardProviderProps) => {
|
|
73
|
+
const [enabled, setEnabled] = useState(initiallyEnabled);
|
|
64
74
|
// animated values
|
|
65
75
|
const progress = useAnimatedValue(0);
|
|
66
76
|
const height = useAnimatedValue(0);
|
|
@@ -69,13 +79,15 @@ export const KeyboardProvider = ({
|
|
|
69
79
|
const heightSV = useSharedValue(0);
|
|
70
80
|
const { setHandlers, broadcast } = useSharedHandlers<KeyboardHandler>();
|
|
71
81
|
// memo
|
|
72
|
-
const context = useMemo(
|
|
82
|
+
const context = useMemo<KeyboardAnimationContext>(
|
|
73
83
|
() => ({
|
|
84
|
+
enabled,
|
|
74
85
|
animated: { progress: progress, height: Animated.multiply(height, -1) },
|
|
75
86
|
reanimated: { progress: progressSV, height: heightSV },
|
|
76
87
|
setHandlers,
|
|
88
|
+
setEnabled,
|
|
77
89
|
}),
|
|
78
|
-
[]
|
|
90
|
+
[enabled]
|
|
79
91
|
);
|
|
80
92
|
const style = useMemo(
|
|
81
93
|
() => [
|
|
@@ -136,10 +148,19 @@ export const KeyboardProvider = ({
|
|
|
136
148
|
},
|
|
137
149
|
[]
|
|
138
150
|
);
|
|
151
|
+
// effects
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (enabled) {
|
|
154
|
+
applyMonkeyPatch();
|
|
155
|
+
} else {
|
|
156
|
+
revertMonkeyPatch();
|
|
157
|
+
}
|
|
158
|
+
}, [enabled]);
|
|
139
159
|
|
|
140
160
|
return (
|
|
141
161
|
<KeyboardContext.Provider value={context}>
|
|
142
162
|
<KeyboardControllerViewAnimated
|
|
163
|
+
enabled={enabled}
|
|
143
164
|
onKeyboardMoveReanimated={handler}
|
|
144
165
|
onKeyboardMoveStart={Platform.OS === 'ios' ? onKeyboardMove : undefined}
|
|
145
166
|
onKeyboardMove={Platform.OS === 'android' ? onKeyboardMove : undefined}
|
|
@@ -5,6 +5,7 @@ export const useKeyboardAnimation = () => {
|
|
|
5
5
|
const heightWhenOpened = useSharedValue(0);
|
|
6
6
|
const height = useSharedValue(0);
|
|
7
7
|
const progress = useSharedValue(0);
|
|
8
|
+
const isClosed = useSharedValue(true);
|
|
8
9
|
|
|
9
10
|
useKeyboardHandler(
|
|
10
11
|
{
|
|
@@ -12,6 +13,7 @@ export const useKeyboardAnimation = () => {
|
|
|
12
13
|
'worklet';
|
|
13
14
|
|
|
14
15
|
if (e.height > 0) {
|
|
16
|
+
isClosed.value = false;
|
|
15
17
|
heightWhenOpened.value = e.height;
|
|
16
18
|
}
|
|
17
19
|
},
|
|
@@ -21,9 +23,14 @@ export const useKeyboardAnimation = () => {
|
|
|
21
23
|
progress.value = e.progress;
|
|
22
24
|
height.value = e.height;
|
|
23
25
|
},
|
|
26
|
+
onEnd: (e) => {
|
|
27
|
+
'worklet';
|
|
28
|
+
|
|
29
|
+
isClosed.value = e.height === 0;
|
|
30
|
+
},
|
|
24
31
|
},
|
|
25
32
|
[]
|
|
26
33
|
);
|
|
27
34
|
|
|
28
|
-
return { height, progress, heightWhenOpened };
|
|
35
|
+
return { height, progress, heightWhenOpened, isClosed };
|
|
29
36
|
};
|
|
@@ -11,6 +11,7 @@ import Reanimated, {
|
|
|
11
11
|
useSharedValue,
|
|
12
12
|
useDerivedValue,
|
|
13
13
|
interpolate,
|
|
14
|
+
runOnUI,
|
|
14
15
|
} from 'react-native-reanimated';
|
|
15
16
|
import { useKeyboardAnimation } from './hooks';
|
|
16
17
|
|
|
@@ -76,11 +77,14 @@ const KeyboardAvoidingView = forwardRef<View, React.PropsWithChildren<Props>>(
|
|
|
76
77
|
return Math.max(frame.value.y + frame.value.height - keyboardY, 0);
|
|
77
78
|
}, [screenHeight, keyboardVerticalOffset]);
|
|
78
79
|
|
|
80
|
+
const onLayoutWorklet = useWorkletCallback((layout: LayoutRectangle) => {
|
|
81
|
+
if (keyboard.isClosed.value) {
|
|
82
|
+
initialFrame.value = layout;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
79
85
|
const onLayout = useCallback<NonNullable<ViewProps['onLayout']>>(
|
|
80
86
|
(e) => {
|
|
81
|
-
|
|
82
|
-
initialFrame.value = e.nativeEvent.layout;
|
|
83
|
-
}
|
|
87
|
+
runOnUI(onLayoutWorklet)(e.nativeEvent.layout);
|
|
84
88
|
onLayoutProps?.(e);
|
|
85
89
|
},
|
|
86
90
|
[onLayoutProps]
|
|
@@ -96,7 +100,7 @@ const KeyboardAvoidingView = forwardRef<View, React.PropsWithChildren<Props>>(
|
|
|
96
100
|
|
|
97
101
|
switch (behavior) {
|
|
98
102
|
case 'height':
|
|
99
|
-
if (
|
|
103
|
+
if (!keyboard.isClosed.value) {
|
|
100
104
|
return {
|
|
101
105
|
height: frame.value.height - bottomHeight,
|
|
102
106
|
flex: 0,
|
package/src/context.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useContext } from 'react';
|
|
1
|
+
import React, { createContext, useContext } from 'react';
|
|
2
2
|
import { Animated } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import type { SharedValue } from 'react-native-reanimated';
|
|
@@ -13,9 +13,11 @@ export type ReanimatedContext = {
|
|
|
13
13
|
height: SharedValue<number>;
|
|
14
14
|
};
|
|
15
15
|
export type KeyboardAnimationContext = {
|
|
16
|
+
enabled: boolean;
|
|
16
17
|
animated: AnimatedContext;
|
|
17
18
|
reanimated: ReanimatedContext;
|
|
18
19
|
setHandlers: (handlers: KeyboardHandlers) => void;
|
|
20
|
+
setEnabled: React.Dispatch<React.SetStateAction<boolean>>;
|
|
19
21
|
};
|
|
20
22
|
const NOOP = () => {};
|
|
21
23
|
const DEFAULT_SHARED_VALUE: SharedValue<number> = {
|
|
@@ -25,6 +27,7 @@ const DEFAULT_SHARED_VALUE: SharedValue<number> = {
|
|
|
25
27
|
modify: NOOP,
|
|
26
28
|
};
|
|
27
29
|
const defaultContext: KeyboardAnimationContext = {
|
|
30
|
+
enabled: true,
|
|
28
31
|
animated: {
|
|
29
32
|
progress: new Animated.Value(0),
|
|
30
33
|
height: new Animated.Value(0),
|
|
@@ -33,7 +36,8 @@ const defaultContext: KeyboardAnimationContext = {
|
|
|
33
36
|
progress: DEFAULT_SHARED_VALUE,
|
|
34
37
|
height: DEFAULT_SHARED_VALUE,
|
|
35
38
|
},
|
|
36
|
-
setHandlers:
|
|
39
|
+
setHandlers: NOOP,
|
|
40
|
+
setEnabled: NOOP,
|
|
37
41
|
};
|
|
38
42
|
export const KeyboardContext = createContext(defaultContext);
|
|
39
43
|
export const useKeyboardContext = () => {
|
package/src/hooks.ts
CHANGED
|
@@ -59,3 +59,9 @@ export function useKeyboardHandler(
|
|
|
59
59
|
useResizeMode();
|
|
60
60
|
useGenericKeyboardHandler(handler, deps);
|
|
61
61
|
}
|
|
62
|
+
|
|
63
|
+
export function useKeyboardController() {
|
|
64
|
+
const context = useKeyboardContext();
|
|
65
|
+
|
|
66
|
+
return { setEnabled: context.setEnabled, enabled: context.enabled };
|
|
67
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,33 +1,39 @@
|
|
|
1
1
|
// @ts-expect-error because there is no corresponding type definition
|
|
2
2
|
import * as NativeAndroidManager from 'react-native/Libraries/Components/StatusBar/NativeStatusBarManagerAndroid';
|
|
3
3
|
|
|
4
|
+
const DefaultNativeAndroidManager = NativeAndroidManager.default;
|
|
4
5
|
const getConstants = NativeAndroidManager.default.getConstants;
|
|
6
|
+
const RCTStatusBarManagerCompat =
|
|
7
|
+
require('./specs/NativeStatusBarManagerCompat').default;
|
|
5
8
|
|
|
6
9
|
// On Android < 11 RN uses legacy API which breaks EdgeToEdge mode in RN, so
|
|
7
10
|
// in order to use library on all available platforms we have to monkey patch
|
|
8
11
|
// default RN implementation and use modern `WindowInsetsControllerCompat`.
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
},
|
|
12
|
+
export const applyMonkeyPatch = () => {
|
|
13
|
+
NativeAndroidManager.default = {
|
|
14
|
+
getConstants,
|
|
15
|
+
setColor(color: number, animated: boolean): void {
|
|
16
|
+
RCTStatusBarManagerCompat.setColor(color, animated);
|
|
17
|
+
},
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
setTranslucent(translucent: boolean): void {
|
|
20
|
+
RCTStatusBarManagerCompat.setTranslucent(translucent);
|
|
21
|
+
},
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
/**
|
|
24
|
+
* - statusBarStyles can be:
|
|
25
|
+
* - 'default'
|
|
26
|
+
* - 'dark-content'
|
|
27
|
+
*/
|
|
28
|
+
setStyle(statusBarStyle?: string): void {
|
|
29
|
+
RCTStatusBarManagerCompat.setStyle(statusBarStyle);
|
|
30
|
+
},
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
setHidden(hidden: boolean): void {
|
|
33
|
+
RCTStatusBarManagerCompat.setHidden(hidden);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export const revertMonkeyPatch = () => {
|
|
38
|
+
NativeAndroidManager.default = DefaultNativeAndroidManager;
|
|
33
39
|
};
|
package/src/monkey-patch.ts
CHANGED
package/src/types.ts
CHANGED