react-native-keyboard-controller 1.2.0 → 1.4.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 (107) hide show
  1. package/android/build.gradle +0 -40
  2. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardAnimationCallback.kt +8 -4
  3. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +44 -8
  4. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManagerImpl.kt +6 -3
  5. package/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt +2 -6
  6. package/ios/.swiftlint.yml +4 -0
  7. package/ios/KeyboardController.xcodeproj/project.pbxproj +2 -2
  8. package/ios/KeyboardControllerModule.mm +1 -1
  9. package/ios/KeyboardControllerView.mm +28 -10
  10. package/ios/KeyboardControllerViewManager.mm +2 -0
  11. package/ios/KeyboardControllerViewManager.swift +4 -1
  12. package/ios/KeyboardMoveEvent.h +1 -0
  13. package/ios/KeyboardMoveEvent.m +2 -1
  14. package/ios/KeyboardMovementObserver.swift +89 -4
  15. package/lib/commonjs/animated.js +44 -63
  16. package/lib/commonjs/animated.js.map +1 -1
  17. package/lib/commonjs/context.js +29 -0
  18. package/lib/commonjs/context.js.map +1 -0
  19. package/lib/commonjs/hooks.js +64 -0
  20. package/lib/commonjs/hooks.js.map +1 -0
  21. package/lib/commonjs/index.js +39 -0
  22. package/lib/commonjs/index.js.map +1 -1
  23. package/lib/commonjs/internal.js +91 -0
  24. package/lib/commonjs/internal.js.map +1 -0
  25. package/lib/commonjs/monkey-patch.js +3 -3
  26. package/lib/commonjs/monkey-patch.js.map +1 -1
  27. package/lib/commonjs/native.js +24 -21
  28. package/lib/commonjs/native.js.map +1 -1
  29. package/lib/commonjs/replicas.js +2 -2
  30. package/lib/commonjs/replicas.js.map +1 -1
  31. package/lib/commonjs/{KeyboardControllerViewNativeComponent.js → specs/KeyboardControllerViewNativeComponent.js} +0 -0
  32. package/lib/commonjs/{KeyboardControllerViewNativeComponent.js.map → specs/KeyboardControllerViewNativeComponent.js.map} +1 -1
  33. package/lib/commonjs/{NativeKeyboardController.js → specs/NativeKeyboardController.js} +0 -0
  34. package/lib/commonjs/{NativeKeyboardController.js.map → specs/NativeKeyboardController.js.map} +0 -0
  35. package/lib/commonjs/{NativeStatusBarManagerCompat.js → specs/NativeStatusBarManagerCompat.js} +0 -0
  36. package/lib/commonjs/{NativeStatusBarManagerCompat.js.map → specs/NativeStatusBarManagerCompat.js.map} +0 -0
  37. package/lib/commonjs/types.js +6 -0
  38. package/lib/commonjs/types.js.map +1 -0
  39. package/lib/commonjs/utils.js +11 -0
  40. package/lib/commonjs/utils.js.map +1 -0
  41. package/lib/module/animated.js +43 -55
  42. package/lib/module/animated.js.map +1 -1
  43. package/lib/module/context.js +19 -0
  44. package/lib/module/context.js.map +1 -0
  45. package/lib/module/hooks.js +39 -0
  46. package/lib/module/hooks.js.map +1 -0
  47. package/lib/module/index.js +3 -0
  48. package/lib/module/index.js.map +1 -1
  49. package/lib/module/internal.js +80 -0
  50. package/lib/module/internal.js.map +1 -0
  51. package/lib/module/monkey-patch.js +4 -3
  52. package/lib/module/monkey-patch.js.map +1 -1
  53. package/lib/module/native.js +23 -17
  54. package/lib/module/native.js.map +1 -1
  55. package/lib/module/replicas.js +1 -1
  56. package/lib/module/replicas.js.map +1 -1
  57. package/lib/module/{KeyboardControllerViewNativeComponent.js → specs/KeyboardControllerViewNativeComponent.js} +0 -0
  58. package/lib/module/{KeyboardControllerViewNativeComponent.js.map → specs/KeyboardControllerViewNativeComponent.js.map} +1 -1
  59. package/lib/module/{NativeKeyboardController.js → specs/NativeKeyboardController.js} +0 -0
  60. package/lib/module/{NativeKeyboardController.js.map → specs/NativeKeyboardController.js.map} +0 -0
  61. package/lib/module/{NativeStatusBarManagerCompat.js → specs/NativeStatusBarManagerCompat.js} +0 -0
  62. package/lib/module/{NativeStatusBarManagerCompat.js.map → specs/NativeStatusBarManagerCompat.js.map} +0 -0
  63. package/lib/module/types.js +2 -0
  64. package/lib/module/types.js.map +1 -0
  65. package/lib/module/utils.js +2 -0
  66. package/lib/module/utils.js.map +1 -0
  67. package/lib/typescript/animated.d.ts +1 -17
  68. package/lib/typescript/context.d.ts +18 -0
  69. package/lib/typescript/hooks.d.ts +8 -0
  70. package/lib/typescript/index.d.ts +3 -0
  71. package/lib/typescript/internal.d.ts +21 -0
  72. package/lib/typescript/native.d.ts +14 -26
  73. package/lib/typescript/{KeyboardControllerViewNativeComponent.d.ts → specs/KeyboardControllerViewNativeComponent.d.ts} +2 -0
  74. package/lib/typescript/{NativeKeyboardController.d.ts → specs/NativeKeyboardController.d.ts} +0 -0
  75. package/lib/typescript/{NativeStatusBarManagerCompat.d.ts → specs/NativeStatusBarManagerCompat.d.ts} +0 -0
  76. package/lib/typescript/types.d.ts +32 -0
  77. package/lib/typescript/utils.d.ts +1 -0
  78. package/package.json +17 -20
  79. package/react-native-keyboard-controller.podspec +2 -1
  80. package/src/animated.tsx +42 -78
  81. package/src/context.ts +31 -0
  82. package/src/hooks.ts +56 -0
  83. package/src/index.ts +3 -0
  84. package/src/internal.ts +87 -0
  85. package/src/{monkey-patch.tsx → monkey-patch.ts} +3 -6
  86. package/src/native.ts +37 -66
  87. package/src/replicas.ts +1 -1
  88. package/src/{KeyboardControllerViewNativeComponent.ts → specs/KeyboardControllerViewNativeComponent.ts} +4 -0
  89. package/src/{NativeKeyboardController.ts → specs/NativeKeyboardController.ts} +0 -0
  90. package/src/{NativeStatusBarManagerCompat.ts → specs/NativeStatusBarManagerCompat.ts} +0 -0
  91. package/src/types.ts +60 -0
  92. package/src/utils.ts +1 -0
  93. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  94. package/android/gradle/wrapper/gradle-wrapper.properties +0 -5
  95. package/android/gradlew +0 -185
  96. package/android/gradlew.bat +0 -89
  97. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerComponentsRegistry.kt +0 -31
  98. package/android/src/main/jni/Android.mk +0 -42
  99. package/android/src/main/jni/KeyboardControllerComponentsRegistry.cpp +0 -71
  100. package/android/src/main/jni/KeyboardControllerComponentsRegistry.h +0 -35
  101. package/android/src/main/jni/OnLoad.cpp +0 -9
  102. package/lib/commonjs/architecture.js +0 -13
  103. package/lib/commonjs/architecture.js.map +0 -1
  104. package/lib/module/architecture.js +0 -5
  105. package/lib/module/architecture.js.map +0 -1
  106. package/lib/typescript/architecture.d.ts +0 -2
  107. package/src/architecture.ts +0 -4
@@ -0,0 +1,18 @@
1
+ /// <reference types="react" />
2
+ import { Animated } from 'react-native';
3
+ import type { SharedValue } from 'react-native-reanimated';
4
+ import type { KeyboardHandlers } from './types';
5
+ export declare type AnimatedContext = {
6
+ progress: Animated.Value;
7
+ height: Animated.AnimatedMultiplication<number>;
8
+ };
9
+ export declare type ReanimatedContext = {
10
+ progress: SharedValue<number>;
11
+ height: SharedValue<number>;
12
+ };
13
+ export declare type KeyboardAnimationContext = {
14
+ animated: AnimatedContext;
15
+ reanimated: ReanimatedContext;
16
+ setHandlers: (handlers: KeyboardHandlers) => void;
17
+ };
18
+ export declare const KeyboardContext: import("react").Context<KeyboardAnimationContext>;
@@ -0,0 +1,8 @@
1
+ import { DependencyList } from 'react';
2
+ import { AnimatedContext, ReanimatedContext } from './context';
3
+ import type { KeyboardHandler } from './types';
4
+ export declare const useResizeMode: () => void;
5
+ export declare const useKeyboardAnimation: () => AnimatedContext;
6
+ export declare const useReanimatedKeyboardAnimation: () => ReanimatedContext;
7
+ export declare function useGenericKeyboardHandler(handler: KeyboardHandler, deps?: DependencyList): void;
8
+ export declare function useKeyboardHandler(handler: KeyboardHandler, deps?: DependencyList): void;
@@ -2,3 +2,6 @@ import './monkey-patch';
2
2
  export * from './native';
3
3
  export * from './animated';
4
4
  export * from './replicas';
5
+ export * from './context';
6
+ export * from './hooks';
7
+ export * from './types';
@@ -0,0 +1,21 @@
1
+ import type { EventWithName, Handlers, NativeEvent } from './types';
2
+ export declare function useAnimatedKeyboardHandler<TContext extends Record<string, unknown>>(handlers: {
3
+ onKeyboardMoveStart?: (e: NativeEvent, context: TContext) => void;
4
+ onKeyboardMove?: (e: NativeEvent, context: TContext) => void;
5
+ onKeyboardMoveEnd?: (e: NativeEvent, context: TContext) => void;
6
+ }, dependencies?: ReadonlyArray<unknown>): (e: import("react-native").NativeSyntheticEvent<EventWithName<NativeEvent>>) => void;
7
+ /**
8
+ * Hook for storing worklet handlers (objects with keys, where values are worklets).
9
+ * Returns methods for setting handlers and broadcasting events in them.
10
+ *
11
+ * T is a generic that looks like:
12
+ * @example
13
+ * {
14
+ * onEvent: () => {},
15
+ * onEvent2: () => {},
16
+ * }
17
+ */
18
+ export declare function useSharedHandlers<T extends Record<string, Function>>(): {
19
+ setHandlers: (handler: Handlers<T>) => void;
20
+ broadcast: (type: keyof T, event: NativeEvent) => void;
21
+ };
@@ -1,34 +1,22 @@
1
- import { NativeSyntheticEvent, ViewProps } from 'react-native';
1
+ import type { KeyboardControllerEvents, KeyboardControllerModule, KeyboardEventData } from './types';
2
2
  export declare enum AndroidSoftInputModes {
3
3
  SOFT_INPUT_ADJUST_NOTHING = 48,
4
4
  SOFT_INPUT_ADJUST_PAN = 32,
5
5
  SOFT_INPUT_ADJUST_RESIZE = 16,
6
- SOFT_INPUT_ADJUST_UNSPECIFIED = 0
6
+ SOFT_INPUT_ADJUST_UNSPECIFIED = 0,
7
+ SOFT_INPUT_IS_FORWARD_NAVIGATION = 256,
8
+ SOFT_INPUT_MASK_ADJUST = 240,
9
+ SOFT_INPUT_MASK_STATE = 15,
10
+ SOFT_INPUT_MODE_CHANGED = 512,
11
+ SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3,
12
+ SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5,
13
+ SOFT_INPUT_STATE_HIDDEN = 2,
14
+ SOFT_INPUT_STATE_UNCHANGED = 1,
15
+ SOFT_INPUT_STATE_UNSPECIFIED = 0,
16
+ SOFT_INPUT_STATE_VISIBLE = 4
7
17
  }
8
- export declare type NativeEvent = {
9
- progress: number;
10
- height: number;
11
- };
12
- export declare type EventWithName<T> = {
13
- eventName: string;
14
- } & T;
15
- export declare type KeyboardControllerProps = {
16
- onKeyboardMove: (e: NativeSyntheticEvent<EventWithName<NativeEvent>>) => void;
17
- onKeyboardMoveReanimated: (e: NativeSyntheticEvent<EventWithName<NativeEvent>>) => void;
18
- statusBarTranslucent?: boolean;
19
- } & ViewProps;
20
- declare type KeyboardController = {
21
- setDefaultMode: () => void;
22
- setInputMode: (mode: AndroidSoftInputModes) => void;
23
- };
24
- export declare const KeyboardController: KeyboardController;
25
- declare type KeyboardControllerEvents = 'keyboardWillShow' | 'keyboardDidShow' | 'keyboardWillHide' | 'keyboardDidHide';
26
- declare type KeyboardEvent = {
27
- height: number;
28
- };
18
+ export declare const KeyboardController: KeyboardControllerModule;
29
19
  export declare const KeyboardEvents: {
30
- addListener: (name: KeyboardControllerEvents, cb: (e: KeyboardEvent) => void) => import("react-native").EmitterSubscription;
20
+ addListener: (name: KeyboardControllerEvents, cb: (e: KeyboardEventData) => void) => import("react-native").EmitterSubscription;
31
21
  };
32
22
  export declare const KeyboardControllerView: any;
33
- export declare const useResizeMode: () => void;
34
- export {};
@@ -8,6 +8,8 @@ declare type KeyboardMoveEvent = Readonly<{
8
8
  export interface NativeProps extends ViewProps {
9
9
  statusBarTranslucent?: boolean;
10
10
  onKeyboardMove?: DirectEventHandler<KeyboardMoveEvent>;
11
+ onKeyboardMoveStart?: DirectEventHandler<KeyboardMoveEvent>;
12
+ onKeyboardMoveEnd?: DirectEventHandler<KeyboardMoveEvent>;
11
13
  }
12
14
  declare const _default: HostComponent<NativeProps>;
13
15
  export default _default;
@@ -0,0 +1,32 @@
1
+ import type { NativeSyntheticEvent, ViewProps } from 'react-native';
2
+ export declare type NativeEvent = {
3
+ progress: number;
4
+ height: number;
5
+ };
6
+ export declare type EventWithName<T> = {
7
+ eventName: string;
8
+ } & T;
9
+ export declare type KeyboardControllerProps = {
10
+ onKeyboardMoveStart?: (e: NativeSyntheticEvent<EventWithName<NativeEvent>>) => void;
11
+ onKeyboardMove?: (e: NativeSyntheticEvent<EventWithName<NativeEvent>>) => void;
12
+ onKeyboardMoveEnd?: (e: NativeSyntheticEvent<EventWithName<NativeEvent>>) => void;
13
+ onKeyboardMoveReanimated: (e: NativeSyntheticEvent<EventWithName<NativeEvent>>) => void;
14
+ statusBarTranslucent?: boolean;
15
+ } & ViewProps;
16
+ export declare type KeyboardControllerModule = {
17
+ setDefaultMode: () => void;
18
+ setInputMode: (mode: number) => void;
19
+ addListener: (eventName: string) => void;
20
+ removeListeners: (count: number) => void;
21
+ };
22
+ export declare type KeyboardControllerEvents = 'keyboardWillShow' | 'keyboardDidShow' | 'keyboardWillHide' | 'keyboardDidHide';
23
+ export declare type KeyboardEventData = {
24
+ height: number;
25
+ };
26
+ export declare type Handlers<T> = Record<string, T | undefined>;
27
+ export declare type KeyboardHandler = {
28
+ onStart?: (e: NativeEvent) => void;
29
+ onMove?: (e: NativeEvent) => void;
30
+ onEnd?: (e: NativeEvent) => void;
31
+ };
32
+ export declare type KeyboardHandlers = Handlers<KeyboardHandler>;
@@ -0,0 +1 @@
1
+ export declare const uuid: () => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-keyboard-controller",
3
- "version": "1.2.0",
3
+ "version": "1.4.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",
@@ -17,6 +17,9 @@
17
17
  "!lib/typescript/example",
18
18
  "!android/build",
19
19
  "!android/.gradle",
20
+ "!android/gradle",
21
+ "!android/gradlew",
22
+ "!android/gradlew.bat",
20
23
  "!ios/build",
21
24
  "!**/__tests__",
22
25
  "!**/__fixtures__",
@@ -55,8 +58,8 @@
55
58
  "@react-native-community/eslint-config": "^2.0.0",
56
59
  "@release-it/conventional-changelog": "^2.0.0",
57
60
  "@types/jest": "^27.4.1",
58
- "@types/react": "^18.0.17",
59
- "@types/react-native": "0.69.5",
61
+ "@types/react": "^18.0.21",
62
+ "@types/react-native": "0.70.4",
60
63
  "commitlint": "^11.0.0",
61
64
  "clang-format": "^1.8.0",
62
65
  "eslint": "^7.2.0",
@@ -66,17 +69,17 @@
66
69
  "jest": "^27.5.1",
67
70
  "pod-install": "^0.1.0",
68
71
  "prettier": "^2.6.2",
69
- "react": "18.0.0",
70
- "react-native": "0.69.4",
72
+ "react": "18.1.0",
73
+ "react-native": "0.70.2",
71
74
  "react-native-builder-bob": "^0.18.0",
72
- "react-native-reanimated": "2.9.1",
75
+ "react-native-reanimated": "2.10.0",
73
76
  "release-it": "^14.2.2",
74
- "typescript": "^4.6.3"
77
+ "typescript": "^4.8.4"
75
78
  },
76
79
  "peerDependencies": {
77
80
  "react": "*",
78
81
  "react-native": "*",
79
- "react-native-reanimated": "^2.3.0"
82
+ "react-native-reanimated": ">=2.3.0"
80
83
  },
81
84
  "jest": {
82
85
  "preset": "react-native",
@@ -153,17 +156,11 @@
153
156
  ]
154
157
  },
155
158
  "codegenConfig": {
156
- "libraries": [
157
- {
158
- "name": "RNKeyboardControllerSpec",
159
- "type": "modules",
160
- "jsSrcsDir": "src"
161
- },
162
- {
163
- "name": "RNKeyboardControllerViewSpec",
164
- "type": "components",
165
- "jsSrcsDir": "src"
166
- }
167
- ]
159
+ "name": "reactnativekeyboardcontroller",
160
+ "type": "all",
161
+ "jsSrcsDir": "./src/specs",
162
+ "android": {
163
+ "javaPackageName": "com.reactnativekeyboardcontroller"
164
+ }
168
165
  }
169
166
  }
@@ -12,7 +12,7 @@ Pod::Spec.new do |s|
12
12
  s.license = package["license"]
13
13
  s.authors = package["author"]
14
14
 
15
- s.platforms = { :ios => "10.0" }
15
+ s.platforms = { :ios => "11.0" }
16
16
  s.source = { :git => "https://github.com/kirillzyusko/react-native-keyboard-controller.git", :tag => "#{s.version}" }
17
17
 
18
18
  s.source_files = "ios/**/*.{h,m,mm,swift}"
@@ -25,6 +25,7 @@ Pod::Spec.new do |s|
25
25
  s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
26
26
  s.pod_target_xcconfig = {
27
27
  "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
28
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
28
29
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
29
30
  }
30
31
 
package/src/animated.tsx CHANGED
@@ -1,17 +1,16 @@
1
- import React, { useContext, useMemo, useRef } from 'react';
2
- import { Animated, StyleSheet, ViewStyle } from 'react-native';
3
- import Reanimated, {
4
- useEvent,
5
- useHandler,
6
- useSharedValue,
7
- } from 'react-native-reanimated';
8
- import {
9
- EventWithName,
1
+ import React, { useMemo, useRef } from 'react';
2
+ import { Animated, Platform, StyleSheet, ViewStyle } from 'react-native';
3
+ import Reanimated, { useSharedValue } from 'react-native-reanimated';
4
+
5
+ import { KeyboardContext } from './context';
6
+ import { useAnimatedKeyboardHandler, useSharedHandlers } from './internal';
7
+ import { KeyboardControllerView } from './native';
8
+
9
+ import type {
10
10
  KeyboardControllerProps,
11
- KeyboardControllerView,
11
+ KeyboardHandler,
12
12
  NativeEvent,
13
- useResizeMode,
14
- } from './native';
13
+ } from './types';
15
14
 
16
15
  const KeyboardControllerViewAnimated = Reanimated.createAnimatedComponent(
17
16
  Animated.createAnimatedComponent(
@@ -19,66 +18,6 @@ const KeyboardControllerViewAnimated = Reanimated.createAnimatedComponent(
19
18
  ) as React.FC<KeyboardControllerProps>
20
19
  );
21
20
 
22
- type AnimatedContext = {
23
- progress: Animated.Value;
24
- height: Animated.Value;
25
- };
26
- type ReanimatedContext = {
27
- progress: Reanimated.SharedValue<number>;
28
- height: Reanimated.SharedValue<number>;
29
- };
30
- type KeyboardAnimationContext = {
31
- animated: AnimatedContext;
32
- reanimated: ReanimatedContext;
33
- };
34
- const defaultContext: KeyboardAnimationContext = {
35
- animated: {
36
- progress: new Animated.Value(0),
37
- height: new Animated.Value(0),
38
- },
39
- reanimated: {
40
- progress: { value: 0 },
41
- height: { value: 0 },
42
- },
43
- };
44
- export const KeyboardContext = React.createContext(defaultContext);
45
-
46
- export const useKeyboardAnimation = (): AnimatedContext => {
47
- useResizeMode();
48
- const context = useContext(KeyboardContext);
49
-
50
- return context.animated;
51
- };
52
-
53
- export const useReanimatedKeyboardAnimation = (): ReanimatedContext => {
54
- useResizeMode();
55
- const context = useContext(KeyboardContext);
56
-
57
- return context.reanimated;
58
- };
59
-
60
- function useAnimatedKeyboardHandler<TContext extends Record<string, unknown>>(
61
- handlers: {
62
- onKeyboardMove?: (e: NativeEvent, context: TContext) => void;
63
- },
64
- dependencies?: ReadonlyArray<unknown>
65
- ) {
66
- const { context, doDependenciesDiffer } = useHandler(handlers, dependencies);
67
-
68
- return useEvent(
69
- (event: EventWithName<NativeEvent>) => {
70
- 'worklet';
71
- const { onKeyboardMove } = handlers;
72
-
73
- if (onKeyboardMove && event.eventName.endsWith('onKeyboardMove')) {
74
- onKeyboardMove(event, context);
75
- }
76
- },
77
- ['onKeyboardMove'],
78
- doDependenciesDiffer
79
- );
80
- }
81
-
82
21
  type Styles = {
83
22
  container: ViewStyle;
84
23
  hidden: ViewStyle;
@@ -112,14 +51,19 @@ export const KeyboardProvider = ({
112
51
  children,
113
52
  statusBarTranslucent,
114
53
  }: KeyboardProviderProps) => {
54
+ // animated values
115
55
  const progress = useRef(new Animated.Value(0)).current;
116
56
  const height = useRef(new Animated.Value(0)).current;
57
+ // shared values
117
58
  const progressSV = useSharedValue(0);
118
59
  const heightSV = useSharedValue(0);
60
+ const { setHandlers, broadcast } = useSharedHandlers<KeyboardHandler>();
61
+ // memo
119
62
  const context = useMemo(
120
63
  () => ({
121
- animated: { progress: progress, height: height },
64
+ animated: { progress: progress, height: Animated.multiply(height, -1) },
122
65
  reanimated: { progress: progressSV, height: heightSV },
66
+ setHandlers,
123
67
  }),
124
68
  []
125
69
  );
@@ -130,7 +74,6 @@ export const KeyboardProvider = ({
130
74
  ],
131
75
  []
132
76
  );
133
-
134
77
  const onKeyboardMove = useMemo(
135
78
  () =>
136
79
  Animated.event(
@@ -146,13 +89,33 @@ export const KeyboardProvider = ({
146
89
  ),
147
90
  []
148
91
  );
149
-
92
+ // handlers
93
+ const updateSharedValues = (event: NativeEvent, platforms: string[]) => {
94
+ 'worklet';
95
+
96
+ if (platforms.includes(Platform.OS)) {
97
+ progressSV.value = event.progress;
98
+ heightSV.value = -event.height;
99
+ }
100
+ };
150
101
  const handler = useAnimatedKeyboardHandler(
151
102
  {
103
+ onKeyboardMoveStart: (event: NativeEvent) => {
104
+ 'worklet';
105
+
106
+ broadcast('onStart', event);
107
+ updateSharedValues(event, ['ios']);
108
+ },
152
109
  onKeyboardMove: (event: NativeEvent) => {
153
110
  'worklet';
154
- progressSV.value = event.progress;
155
- heightSV.value = event.height;
111
+
112
+ broadcast('onMove', event);
113
+ updateSharedValues(event, ['android']);
114
+ },
115
+ onKeyboardMoveEnd: (event: NativeEvent) => {
116
+ 'worklet';
117
+
118
+ broadcast('onEnd', event);
156
119
  },
157
120
  },
158
121
  []
@@ -162,7 +125,8 @@ export const KeyboardProvider = ({
162
125
  <KeyboardContext.Provider value={context}>
163
126
  <KeyboardControllerViewAnimated
164
127
  onKeyboardMoveReanimated={handler}
165
- onKeyboardMove={onKeyboardMove}
128
+ onKeyboardMoveStart={Platform.OS === 'ios' ? onKeyboardMove : undefined}
129
+ onKeyboardMove={Platform.OS === 'android' ? onKeyboardMove : undefined}
166
130
  statusBarTranslucent={statusBarTranslucent}
167
131
  style={styles.container}
168
132
  >
package/src/context.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { createContext } from 'react';
2
+ import { Animated } from 'react-native';
3
+
4
+ import type { SharedValue } from 'react-native-reanimated';
5
+ import type { KeyboardHandlers } from './types';
6
+
7
+ export type AnimatedContext = {
8
+ progress: Animated.Value;
9
+ height: Animated.AnimatedMultiplication<number>;
10
+ };
11
+ export type ReanimatedContext = {
12
+ progress: SharedValue<number>;
13
+ height: SharedValue<number>;
14
+ };
15
+ export type KeyboardAnimationContext = {
16
+ animated: AnimatedContext;
17
+ reanimated: ReanimatedContext;
18
+ setHandlers: (handlers: KeyboardHandlers) => void;
19
+ };
20
+ const defaultContext: KeyboardAnimationContext = {
21
+ animated: {
22
+ progress: new Animated.Value(0),
23
+ height: new Animated.Value(0),
24
+ },
25
+ reanimated: {
26
+ progress: { value: 0 },
27
+ height: { value: 0 },
28
+ },
29
+ setHandlers: () => {},
30
+ };
31
+ export const KeyboardContext = createContext(defaultContext);
package/src/hooks.ts ADDED
@@ -0,0 +1,56 @@
1
+ import { DependencyList, useContext, useEffect } from 'react';
2
+
3
+ import { AnimatedContext, KeyboardContext, ReanimatedContext } from './context';
4
+ import { AndroidSoftInputModes, KeyboardController } from './native';
5
+ import { uuid } from './utils';
6
+
7
+ import type { KeyboardHandler } from './types';
8
+
9
+ export const useResizeMode = () => {
10
+ useEffect(() => {
11
+ KeyboardController.setInputMode(
12
+ AndroidSoftInputModes.SOFT_INPUT_ADJUST_RESIZE
13
+ );
14
+
15
+ return () => KeyboardController.setDefaultMode();
16
+ }, []);
17
+ };
18
+
19
+ export const useKeyboardAnimation = (): AnimatedContext => {
20
+ useResizeMode();
21
+ const context = useContext(KeyboardContext);
22
+
23
+ return context.animated;
24
+ };
25
+
26
+ export const useReanimatedKeyboardAnimation = (): ReanimatedContext => {
27
+ useResizeMode();
28
+ const context = useContext(KeyboardContext);
29
+
30
+ return context.reanimated;
31
+ };
32
+
33
+ export function useGenericKeyboardHandler(
34
+ handler: KeyboardHandler,
35
+ deps?: DependencyList
36
+ ) {
37
+ const context = useContext(KeyboardContext);
38
+
39
+ useEffect(() => {
40
+ const key = uuid();
41
+
42
+ context.setHandlers({ [key]: handler });
43
+
44
+ return () => {
45
+ context.setHandlers({ [key]: undefined });
46
+ };
47
+ }, deps);
48
+ }
49
+
50
+ export function useKeyboardHandler(
51
+ handler: KeyboardHandler,
52
+ deps?: DependencyList
53
+ ) {
54
+ useResizeMode();
55
+ useGenericKeyboardHandler(handler, deps);
56
+ }
package/src/index.ts CHANGED
@@ -3,3 +3,6 @@ import './monkey-patch';
3
3
  export * from './native';
4
4
  export * from './animated';
5
5
  export * from './replicas';
6
+ export * from './context';
7
+ export * from './hooks';
8
+ export * from './types';
@@ -0,0 +1,87 @@
1
+ import { useCallback, useRef } from 'react';
2
+ import { useEvent, useHandler, useSharedValue } from 'react-native-reanimated';
3
+
4
+ import type { EventWithName, Handlers, NativeEvent } from './types';
5
+
6
+ export function useAnimatedKeyboardHandler<
7
+ TContext extends Record<string, unknown>
8
+ >(
9
+ handlers: {
10
+ onKeyboardMoveStart?: (e: NativeEvent, context: TContext) => void;
11
+ onKeyboardMove?: (e: NativeEvent, context: TContext) => void;
12
+ onKeyboardMoveEnd?: (e: NativeEvent, context: TContext) => void;
13
+ },
14
+ dependencies?: ReadonlyArray<unknown>
15
+ ) {
16
+ const { context, doDependenciesDiffer } = useHandler(handlers, dependencies);
17
+
18
+ return useEvent(
19
+ (event: EventWithName<NativeEvent>) => {
20
+ 'worklet';
21
+ const { onKeyboardMoveStart, onKeyboardMove, onKeyboardMoveEnd } =
22
+ handlers;
23
+
24
+ if (
25
+ onKeyboardMoveStart &&
26
+ event.eventName.endsWith('onKeyboardMoveStart')
27
+ ) {
28
+ onKeyboardMoveStart(event, context);
29
+ }
30
+
31
+ if (onKeyboardMove && event.eventName.endsWith('onKeyboardMove')) {
32
+ onKeyboardMove(event, context);
33
+ }
34
+
35
+ if (onKeyboardMoveEnd && event.eventName.endsWith('onKeyboardMoveEnd')) {
36
+ onKeyboardMoveEnd(event, context);
37
+ }
38
+ },
39
+ ['onKeyboardMoveStart', 'onKeyboardMove', 'onKeyboardMoveEnd'],
40
+ doDependenciesDiffer
41
+ );
42
+ }
43
+
44
+ /**
45
+ * Hook for storing worklet handlers (objects with keys, where values are worklets).
46
+ * Returns methods for setting handlers and broadcasting events in them.
47
+ *
48
+ * T is a generic that looks like:
49
+ * @example
50
+ * {
51
+ * onEvent: () => {},
52
+ * onEvent2: () => {},
53
+ * }
54
+ */
55
+ export function useSharedHandlers<T extends Record<string, Function>>() {
56
+ const handlers = useSharedValue<Handlers<T>>({});
57
+ const jsHandlers = useRef<Handlers<T>>({});
58
+
59
+ // since js -> worklet -> js call is asynchronous, we can not write handlers
60
+ // straight into shared variable (using current shared value as a previous result),
61
+ // since there may be a race condition in a call, and closure may have out-of-dated
62
+ // values. As a result, some of handlers may be not written to "all handlers" object.
63
+ // Below we are writing all handlers to `ref` and afterwards synchronize them with
64
+ // shared value (since `refs` are not referring to actual value in worklets).
65
+ // This approach allow us to update synchronously handlers in js thread (and it assures,
66
+ // that it will have all of them) and then update them in worklet thread (calls are
67
+ // happening in FIFO order, so we will always have actual value).
68
+ const updateSharedHandlers = () => {
69
+ handlers.value = jsHandlers.current;
70
+ };
71
+ const setHandlers = useCallback((handler: Handlers<T>) => {
72
+ jsHandlers.current = {
73
+ ...jsHandlers.current,
74
+ ...handler,
75
+ };
76
+ updateSharedHandlers();
77
+ }, []);
78
+ const broadcast = (type: keyof T, event: NativeEvent) => {
79
+ 'worklet';
80
+
81
+ Object.keys(handlers.value).forEach((key) =>
82
+ handlers.value[key]?.[type]?.(event)
83
+ );
84
+ };
85
+
86
+ return { setHandlers, broadcast };
87
+ }
@@ -1,14 +1,11 @@
1
- import { NativeModules, Platform } from 'react-native';
1
+ import { Platform } from 'react-native';
2
2
  // @ts-expect-error because there is no corresponding type definition
3
3
  import * as NativeAndroidManager from 'react-native/Libraries/Components/StatusBar/NativeStatusBarManagerAndroid';
4
4
 
5
- import { isTurboModuleEnabled } from './architecture';
6
-
7
5
  const getConstants = NativeAndroidManager.default.getConstants;
8
6
 
9
- const RCTStatusBarManagerCompat = isTurboModuleEnabled
10
- ? require('./NativeStatusBarManagerCompat').default
11
- : NativeModules.StatusBarManagerCompat;
7
+ const RCTStatusBarManagerCompat =
8
+ require('./specs/NativeStatusBarManagerCompat').default;
12
9
 
13
10
  // On Android < 11 RN uses legacy API which breaks EdgeToEdge mode in RN, so
14
11
  // in order to use library on all available platforms we have to monkey patch