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.
Files changed (64) hide show
  1. package/README.md +1 -0
  2. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +5 -0
  3. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +4 -0
  4. package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +111 -49
  5. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +5 -0
  6. package/ios/KeyboardControllerView.mm +16 -1
  7. package/ios/KeyboardControllerViewManager.mm +4 -0
  8. package/ios/KeyboardControllerViewManager.swift +11 -1
  9. package/lib/commonjs/animated.js +17 -3
  10. package/lib/commonjs/animated.js.map +1 -1
  11. package/lib/commonjs/components/KeyboardAvoidingView/hooks.js +9 -1
  12. package/lib/commonjs/components/KeyboardAvoidingView/hooks.js.map +1 -1
  13. package/lib/commonjs/components/KeyboardAvoidingView/index.js +7 -4
  14. package/lib/commonjs/components/KeyboardAvoidingView/index.js.map +1 -1
  15. package/lib/commonjs/context.js +3 -1
  16. package/lib/commonjs/context.js.map +1 -1
  17. package/lib/commonjs/hooks.js +8 -0
  18. package/lib/commonjs/hooks.js.map +1 -1
  19. package/lib/commonjs/index.js +0 -1
  20. package/lib/commonjs/index.js.map +1 -1
  21. package/lib/commonjs/monkey-patch.android.js +32 -20
  22. package/lib/commonjs/monkey-patch.android.js.map +1 -1
  23. package/lib/commonjs/monkey-patch.js +11 -1
  24. package/lib/commonjs/monkey-patch.js.map +1 -1
  25. package/lib/commonjs/specs/KeyboardControllerViewNativeComponent.js.map +1 -1
  26. package/lib/commonjs/types.js.map +1 -1
  27. package/lib/module/animated.js +18 -4
  28. package/lib/module/animated.js.map +1 -1
  29. package/lib/module/components/KeyboardAvoidingView/hooks.js +9 -1
  30. package/lib/module/components/KeyboardAvoidingView/hooks.js.map +1 -1
  31. package/lib/module/components/KeyboardAvoidingView/index.js +8 -5
  32. package/lib/module/components/KeyboardAvoidingView/index.js.map +1 -1
  33. package/lib/module/context.js +3 -1
  34. package/lib/module/context.js.map +1 -1
  35. package/lib/module/hooks.js +7 -0
  36. package/lib/module/hooks.js.map +1 -1
  37. package/lib/module/index.js +0 -1
  38. package/lib/module/index.js.map +1 -1
  39. package/lib/module/monkey-patch.android.js +26 -20
  40. package/lib/module/monkey-patch.android.js.map +1 -1
  41. package/lib/module/monkey-patch.js +3 -0
  42. package/lib/module/monkey-patch.js.map +1 -1
  43. package/lib/module/specs/KeyboardControllerViewNativeComponent.js.map +1 -1
  44. package/lib/module/types.js.map +1 -1
  45. package/lib/typescript/animated.d.ts +8 -1
  46. package/lib/typescript/components/KeyboardAvoidingView/hooks.d.ts +1 -0
  47. package/lib/typescript/context.d.ts +4 -2
  48. package/lib/typescript/hooks.d.ts +4 -0
  49. package/lib/typescript/index.d.ts +0 -1
  50. package/lib/typescript/monkey-patch.android.d.ts +2 -1
  51. package/lib/typescript/monkey-patch.d.ts +2 -0
  52. package/lib/typescript/specs/KeyboardControllerViewNativeComponent.d.ts +1 -0
  53. package/lib/typescript/types.d.ts +1 -0
  54. package/package.json +1 -1
  55. package/src/animated.tsx +25 -4
  56. package/src/components/KeyboardAvoidingView/hooks.ts +8 -1
  57. package/src/components/KeyboardAvoidingView/index.tsx +8 -4
  58. package/src/context.ts +6 -2
  59. package/src/hooks.ts +6 -0
  60. package/src/index.ts +0 -2
  61. package/src/monkey-patch.android.ts +27 -21
  62. package/src/monkey-patch.ts +3 -0
  63. package/src/specs/KeyboardControllerViewNativeComponent.ts +1 -0
  64. package/src/types.ts +1 -0
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
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: import("react").Context<KeyboardAnimationContext>;
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,4 +1,3 @@
1
- import './monkey-patch';
2
1
  export * from './bindings';
3
2
  export * from './animated';
4
3
  export * from './replicas';
@@ -1 +1,2 @@
1
- export {};
1
+ export declare const applyMonkeyPatch: () => void;
2
+ export declare const revertMonkeyPatch: () => void;
@@ -0,0 +1,2 @@
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-keyboard-controller",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Keyboard manager which works in identical way on both iOS and Android",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
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
- if (initialFrame.value === null) {
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 (bottomHeight > 0) {
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,5 +1,3 @@
1
- import './monkey-patch';
2
-
3
1
  export * from './bindings';
4
2
  export * from './animated';
5
3
  export * from './replicas';
@@ -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 RCTStatusBarManagerCompat =
10
- require('./specs/NativeStatusBarManagerCompat').default;
11
- NativeAndroidManager.default = {
12
- getConstants,
13
- setColor(color: number, animated: boolean): void {
14
- RCTStatusBarManagerCompat.setColor(color, animated);
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
- setTranslucent(translucent: boolean): void {
18
- RCTStatusBarManagerCompat.setTranslucent(translucent);
19
- },
19
+ setTranslucent(translucent: boolean): void {
20
+ RCTStatusBarManagerCompat.setTranslucent(translucent);
21
+ },
20
22
 
21
- /**
22
- * - statusBarStyles can be:
23
- * - 'default'
24
- * - 'dark-content'
25
- */
26
- setStyle(statusBarStyle?: string): void {
27
- RCTStatusBarManagerCompat.setStyle(statusBarStyle);
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
- setHidden(hidden: boolean): void {
31
- RCTStatusBarManagerCompat.setHidden(hidden);
32
- },
32
+ setHidden(hidden: boolean): void {
33
+ RCTStatusBarManagerCompat.setHidden(hidden);
34
+ },
35
+ };
36
+ };
37
+ export const revertMonkeyPatch = () => {
38
+ NativeAndroidManager.default = DefaultNativeAndroidManager;
33
39
  };
@@ -1 +1,4 @@
1
1
  // stub for all platforms
2
+ const NOOP = () => {};
3
+ export const applyMonkeyPatch = NOOP;
4
+ export const revertMonkeyPatch = NOOP;
@@ -16,6 +16,7 @@ type KeyboardMoveEvent = Readonly<{
16
16
 
17
17
  export interface NativeProps extends ViewProps {
18
18
  // props
19
+ enabled?: boolean;
19
20
  statusBarTranslucent?: boolean;
20
21
  navigationBarTranslucent?: boolean;
21
22
  // callbacks
package/src/types.ts CHANGED
@@ -17,6 +17,7 @@ export type EventWithName<T> = {
17
17
 
18
18
  // native View/Module declarations
19
19
  export type KeyboardControllerProps = {
20
+ enabled?: boolean;
20
21
  onKeyboardMoveStart?: (
21
22
  e: NativeSyntheticEvent<EventWithName<NativeEvent>>
22
23
  ) => void;