react-native-keyboard-controller 1.9.5 → 1.10.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 (119) hide show
  1. package/README.md +1 -1
  2. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +4 -0
  3. package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputTextChangedEvent.kt +20 -0
  4. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt +36 -0
  5. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/WindowInsetsAnimationCompat.kt +7 -0
  6. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt +17 -0
  7. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +12 -0
  8. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +2 -0
  9. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +13 -0
  10. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +5 -0
  11. package/ios/KeyboardController.xcodeproj/project.pbxproj +10 -0
  12. package/ios/KeyboardControllerModule.mm +14 -0
  13. package/ios/events/FocusedInputTextChangedEvent.h +16 -0
  14. package/ios/events/FocusedInputTextChangedEvent.m +72 -0
  15. package/ios/observers/FocusedInputObserver.swift +29 -14
  16. package/ios/observers/TextChangeObserver.swift +41 -0
  17. package/ios/views/KeyboardControllerView.mm +53 -31
  18. package/ios/views/KeyboardControllerViewManager.mm +1 -0
  19. package/ios/views/KeyboardControllerViewManager.swift +21 -10
  20. package/jest/index.js +2 -0
  21. package/lib/commonjs/animated.js +20 -14
  22. package/lib/commonjs/animated.js.map +1 -1
  23. package/lib/commonjs/bindings.js +1 -0
  24. package/lib/commonjs/bindings.js.map +1 -1
  25. package/lib/commonjs/components/KeyboardAvoidingView/index.js +7 -4
  26. package/lib/commonjs/components/KeyboardAvoidingView/index.js.map +1 -1
  27. package/lib/commonjs/components/KeyboardAwareScrollView/index.js +199 -0
  28. package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -0
  29. package/lib/commonjs/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js +100 -0
  30. package/lib/commonjs/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js.map +1 -0
  31. package/lib/commonjs/components/KeyboardAwareScrollView/utils.js +28 -0
  32. package/lib/commonjs/components/KeyboardAwareScrollView/utils.js.map +1 -0
  33. package/lib/commonjs/components/KeyboardStickyView/index.js +0 -1
  34. package/lib/commonjs/components/KeyboardStickyView/index.js.map +1 -1
  35. package/lib/commonjs/components/index.js +7 -0
  36. package/lib/commonjs/components/index.js.map +1 -1
  37. package/lib/commonjs/context.js +2 -1
  38. package/lib/commonjs/context.js.map +1 -1
  39. package/lib/commonjs/hooks.js +17 -2
  40. package/lib/commonjs/hooks.js.map +1 -1
  41. package/lib/commonjs/index.js +8 -1
  42. package/lib/commonjs/index.js.map +1 -1
  43. package/lib/commonjs/internal.js +2 -5
  44. package/lib/commonjs/internal.js.map +1 -1
  45. package/lib/commonjs/reanimated.js +5 -3
  46. package/lib/commonjs/reanimated.js.map +1 -1
  47. package/lib/commonjs/reanimated.native.js +20 -3
  48. package/lib/commonjs/reanimated.native.js.map +1 -1
  49. package/lib/commonjs/replicas.js +3 -1
  50. package/lib/commonjs/replicas.js.map +1 -1
  51. package/lib/commonjs/specs/KeyboardControllerViewNativeComponent.js.map +1 -1
  52. package/lib/commonjs/specs/NativeKeyboardController.js.map +1 -1
  53. package/lib/commonjs/types.js.map +1 -1
  54. package/lib/module/animated.js +21 -15
  55. package/lib/module/animated.js.map +1 -1
  56. package/lib/module/bindings.js +1 -0
  57. package/lib/module/bindings.js.map +1 -1
  58. package/lib/module/components/KeyboardAvoidingView/index.js +8 -5
  59. package/lib/module/components/KeyboardAvoidingView/index.js.map +1 -1
  60. package/lib/module/components/KeyboardAwareScrollView/index.js +190 -0
  61. package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -0
  62. package/lib/module/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js +93 -0
  63. package/lib/module/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.js.map +1 -0
  64. package/lib/module/components/KeyboardAwareScrollView/utils.js +21 -0
  65. package/lib/module/components/KeyboardAwareScrollView/utils.js.map +1 -0
  66. package/lib/module/components/KeyboardStickyView/index.js +0 -1
  67. package/lib/module/components/KeyboardStickyView/index.js.map +1 -1
  68. package/lib/module/components/index.js +1 -0
  69. package/lib/module/components/index.js.map +1 -1
  70. package/lib/module/context.js +2 -1
  71. package/lib/module/context.js.map +1 -1
  72. package/lib/module/hooks.js +16 -2
  73. package/lib/module/hooks.js.map +1 -1
  74. package/lib/module/index.js +1 -1
  75. package/lib/module/index.js.map +1 -1
  76. package/lib/module/internal.js +2 -5
  77. package/lib/module/internal.js.map +1 -1
  78. package/lib/module/reanimated.js +2 -1
  79. package/lib/module/reanimated.js.map +1 -1
  80. package/lib/module/reanimated.native.js +17 -1
  81. package/lib/module/reanimated.native.js.map +1 -1
  82. package/lib/module/replicas.js +5 -3
  83. package/lib/module/replicas.js.map +1 -1
  84. package/lib/module/specs/KeyboardControllerViewNativeComponent.js.map +1 -1
  85. package/lib/module/specs/NativeKeyboardController.js.map +1 -1
  86. package/lib/module/types.js.map +1 -1
  87. package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +45 -0
  88. package/lib/typescript/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.d.ts +6 -0
  89. package/lib/typescript/components/KeyboardAwareScrollView/utils.d.ts +1 -0
  90. package/lib/typescript/components/index.d.ts +1 -0
  91. package/lib/typescript/context.d.ts +3 -2
  92. package/lib/typescript/hooks.d.ts +2 -1
  93. package/lib/typescript/index.d.ts +1 -1
  94. package/lib/typescript/internal.d.ts +8 -5
  95. package/lib/typescript/reanimated.d.ts +3 -2
  96. package/lib/typescript/reanimated.native.d.ts +3 -2
  97. package/lib/typescript/specs/KeyboardControllerViewNativeComponent.d.ts +4 -0
  98. package/lib/typescript/specs/NativeKeyboardController.d.ts +1 -0
  99. package/lib/typescript/types.d.ts +15 -2
  100. package/package.json +5 -2
  101. package/react-native-keyboard-controller.podspec +1 -1
  102. package/src/animated.tsx +27 -10
  103. package/src/bindings.ts +1 -0
  104. package/src/components/KeyboardAvoidingView/index.tsx +7 -5
  105. package/src/components/KeyboardAwareScrollView/index.tsx +262 -0
  106. package/src/components/KeyboardAwareScrollView/useSmoothKeyboardHandler.ts +123 -0
  107. package/src/components/KeyboardAwareScrollView/utils.ts +26 -0
  108. package/src/components/KeyboardStickyView/index.tsx +1 -6
  109. package/src/components/index.ts +1 -0
  110. package/src/context.ts +9 -3
  111. package/src/hooks.ts +20 -3
  112. package/src/index.ts +5 -1
  113. package/src/internal.ts +17 -8
  114. package/src/reanimated.native.ts +27 -2
  115. package/src/reanimated.ts +8 -2
  116. package/src/replicas.ts +4 -3
  117. package/src/specs/KeyboardControllerViewNativeComponent.ts +7 -0
  118. package/src/specs/NativeKeyboardController.ts +1 -0
  119. package/src/types.ts +28 -2
package/src/context.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  import { createContext, useContext } from 'react';
2
2
  import { Animated } from 'react-native';
3
3
 
4
- import type { FocusedInputLayoutChangedEvent, KeyboardHandlers } from './types';
4
+ import type {
5
+ FocusedInputHandlers,
6
+ FocusedInputLayoutChangedEvent,
7
+ KeyboardHandlers,
8
+ } from './types';
5
9
  import type React from 'react';
6
10
  import type { SharedValue } from 'react-native-reanimated';
7
11
 
@@ -18,7 +22,8 @@ export type KeyboardAnimationContext = {
18
22
  animated: AnimatedContext;
19
23
  reanimated: ReanimatedContext;
20
24
  layout: SharedValue<FocusedInputLayoutChangedEvent | null>;
21
- setHandlers: (handlers: KeyboardHandlers) => void;
25
+ setKeyboardHandlers: (handlers: KeyboardHandlers) => void;
26
+ setInputHandlers: (handlers: FocusedInputHandlers) => void;
22
27
  setEnabled: React.Dispatch<React.SetStateAction<boolean>>;
23
28
  };
24
29
  const NOOP = () => {};
@@ -43,7 +48,8 @@ const defaultContext: KeyboardAnimationContext = {
43
48
  height: DEFAULT_SHARED_VALUE,
44
49
  },
45
50
  layout: DEFAULT_LAYOUT,
46
- setHandlers: NOOP,
51
+ setKeyboardHandlers: NOOP,
52
+ setInputHandlers: NOOP,
47
53
  setEnabled: NOOP,
48
54
  };
49
55
  export const KeyboardContext = createContext(defaultContext);
package/src/hooks.ts CHANGED
@@ -6,7 +6,7 @@ import { useKeyboardContext } from './context';
6
6
  import { uuid } from './utils';
7
7
 
8
8
  import type { AnimatedContext, ReanimatedContext } from './context';
9
- import type { KeyboardHandler } from './types';
9
+ import type { FocusedInputHandler, KeyboardHandler } from './types';
10
10
  import type { DependencyList } from 'react';
11
11
 
12
12
  export const useResizeMode = () => {
@@ -42,10 +42,10 @@ export function useGenericKeyboardHandler(
42
42
  useEffect(() => {
43
43
  const key = uuid();
44
44
 
45
- context.setHandlers({ [key]: handler });
45
+ context.setKeyboardHandlers({ [key]: handler });
46
46
 
47
47
  return () => {
48
- context.setHandlers({ [key]: undefined });
48
+ context.setKeyboardHandlers({ [key]: undefined });
49
49
  };
50
50
  }, deps);
51
51
  }
@@ -69,3 +69,20 @@ export function useReanimatedFocusedInput() {
69
69
 
70
70
  return { input: context.layout };
71
71
  }
72
+
73
+ export function useFocusedInputHandler(
74
+ handler?: FocusedInputHandler,
75
+ deps?: DependencyList
76
+ ) {
77
+ const context = useKeyboardContext();
78
+
79
+ useEffect(() => {
80
+ const key = uuid();
81
+
82
+ context.setInputHandlers({ [key]: handler });
83
+
84
+ return () => {
85
+ context.setInputHandlers({ [key]: undefined });
86
+ };
87
+ }, deps);
88
+ }
package/src/index.ts CHANGED
@@ -6,4 +6,8 @@ export * from './hooks';
6
6
  export * from './constants';
7
7
  export * from './types';
8
8
 
9
- export { KeyboardAvoidingView, KeyboardStickyView } from './components';
9
+ export {
10
+ KeyboardAvoidingView,
11
+ KeyboardStickyView,
12
+ KeyboardAwareScrollView,
13
+ } from './components';
package/src/internal.ts CHANGED
@@ -2,7 +2,13 @@ import { useCallback, useRef } from 'react';
2
2
  import { Animated } from 'react-native';
3
3
  import { useSharedValue } from 'react-native-reanimated';
4
4
 
5
- import type { Handlers, NativeEvent } from './types';
5
+ import type { Handlers } from './types';
6
+
7
+ type UntypedHandler = Record<string, (event: never) => void>;
8
+ type SharedHandlersReturnType<T extends UntypedHandler> = [
9
+ (handler: Handlers<T>) => void,
10
+ <K extends keyof T>(type: K, event: Parameters<T[K]>[0]) => void
11
+ ];
6
12
 
7
13
  /**
8
14
  * Hook for storing worklet handlers (objects with keys, where values are worklets).
@@ -16,8 +22,8 @@ import type { Handlers, NativeEvent } from './types';
16
22
  * }
17
23
  */
18
24
  export function useSharedHandlers<
19
- T extends Record<string, (event: NativeEvent) => void>
20
- >() {
25
+ T extends UntypedHandler
26
+ >(): SharedHandlersReturnType<T> {
21
27
  const handlers = useSharedValue<Handlers<T>>({});
22
28
  const jsHandlers = useRef<Handlers<T>>({});
23
29
 
@@ -40,15 +46,18 @@ export function useSharedHandlers<
40
46
  };
41
47
  updateSharedHandlers();
42
48
  }, []);
43
- const broadcast = (type: keyof T, event: NativeEvent) => {
49
+ const broadcast = <K extends keyof T>(
50
+ type: K,
51
+ event: Parameters<T[K]>[0]
52
+ ) => {
44
53
  'worklet';
45
54
 
46
- Object.keys(handlers.value).forEach((key) =>
47
- handlers.value[key]?.[type]?.(event)
48
- );
55
+ Object.keys(handlers.value).forEach((key) => {
56
+ handlers.value[key]?.[type]?.(event);
57
+ });
49
58
  };
50
59
 
51
- return { setHandlers, broadcast };
60
+ return [setHandlers, broadcast];
52
61
  }
53
62
 
54
63
  /**
@@ -2,8 +2,10 @@ import { useEvent, useHandler } from 'react-native-reanimated';
2
2
 
3
3
  import type {
4
4
  EventWithName,
5
- FocusedInputHandlerHook,
6
5
  FocusedInputLayoutChangedEvent,
6
+ FocusedInputLayoutHandlerHook,
7
+ FocusedInputTextChangedEvent,
8
+ FocusedInputTextHandlerHook,
7
9
  KeyboardHandlerHook,
8
10
  NativeEvent,
9
11
  } from './types';
@@ -56,7 +58,7 @@ export const useAnimatedKeyboardHandler: KeyboardHandlerHook<
56
58
  );
57
59
  };
58
60
 
59
- export const useFocusedInputHandler: FocusedInputHandlerHook<
61
+ export const useFocusedInputLayoutHandler: FocusedInputLayoutHandlerHook<
60
62
  Record<string, unknown>,
61
63
  EventWithName<FocusedInputLayoutChangedEvent>
62
64
  > = (handlers, dependencies) => {
@@ -78,3 +80,26 @@ export const useFocusedInputHandler: FocusedInputHandlerHook<
78
80
  doDependenciesDiffer
79
81
  );
80
82
  };
83
+
84
+ export const useFocusedInputTextHandler: FocusedInputTextHandlerHook<
85
+ Record<string, unknown>,
86
+ EventWithName<FocusedInputTextChangedEvent>
87
+ > = (handlers, dependencies) => {
88
+ const { context, doDependenciesDiffer } = useHandler(handlers, dependencies);
89
+
90
+ return useEvent(
91
+ (event) => {
92
+ 'worklet';
93
+ const { onFocusedInputTextChanged } = handlers;
94
+
95
+ if (
96
+ onFocusedInputTextChanged &&
97
+ event.eventName.endsWith('onFocusedInputTextChanged')
98
+ ) {
99
+ onFocusedInputTextChanged(event, context);
100
+ }
101
+ },
102
+ ['onFocusedInputTextChanged'],
103
+ doDependenciesDiffer
104
+ );
105
+ };
package/src/reanimated.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import type {
2
2
  EventWithName,
3
- FocusedInputHandlerHook,
4
3
  FocusedInputLayoutChangedEvent,
4
+ FocusedInputLayoutHandlerHook,
5
+ FocusedInputTextChangedEvent,
6
+ FocusedInputTextHandlerHook,
5
7
  KeyboardHandlerHook,
6
8
  NativeEvent,
7
9
  } from './types';
@@ -11,7 +13,11 @@ export const useAnimatedKeyboardHandler: KeyboardHandlerHook<
11
13
  Record<string, unknown>,
12
14
  EventWithName<NativeEvent>
13
15
  > = NOOP;
14
- export const useFocusedInputHandler: FocusedInputHandlerHook<
16
+ export const useFocusedInputLayoutHandler: FocusedInputLayoutHandlerHook<
15
17
  Record<string, unknown>,
16
18
  EventWithName<FocusedInputLayoutChangedEvent>
17
19
  > = NOOP;
20
+ export const useFocusedInputTextHandler: FocusedInputTextHandlerHook<
21
+ Record<string, unknown>,
22
+ EventWithName<FocusedInputTextChangedEvent>
23
+ > = NOOP;
package/src/replicas.ts CHANGED
@@ -1,11 +1,10 @@
1
- import { useEffect, useMemo, useRef } from 'react';
1
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
2
2
  import { Animated, Easing, Keyboard, Platform } from 'react-native';
3
3
  import {
4
4
  runOnUI,
5
5
  useAnimatedReaction,
6
6
  useDerivedValue,
7
7
  useSharedValue,
8
- useWorkletCallback,
9
8
  withSpring,
10
9
  } from 'react-native-reanimated';
11
10
 
@@ -111,7 +110,9 @@ export const useReanimatedKeyboardAnimationReplica = () => {
111
110
 
112
111
  const progress = useDerivedValue(() => height.value / heightEvent.value);
113
112
 
114
- const handler = useWorkletCallback((_height: number) => {
113
+ const handler = useCallback((_height: number) => {
114
+ 'worklet';
115
+
115
116
  heightEvent.value = _height;
116
117
  }, []);
117
118
 
@@ -27,17 +27,24 @@ type FocusedInputLayoutChangedEvent = Readonly<{
27
27
  };
28
28
  }>;
29
29
 
30
+ type FocusedInputTextChangedEvent = Readonly<{
31
+ text: string;
32
+ }>;
33
+
30
34
  export interface NativeProps extends ViewProps {
31
35
  // props
32
36
  enabled?: boolean;
33
37
  statusBarTranslucent?: boolean;
34
38
  navigationBarTranslucent?: boolean;
35
39
  // callbacks
40
+ /// keyboard
36
41
  onKeyboardMoveStart?: DirectEventHandler<KeyboardMoveEvent>;
37
42
  onKeyboardMove?: DirectEventHandler<KeyboardMoveEvent>;
38
43
  onKeyboardMoveEnd?: DirectEventHandler<KeyboardMoveEvent>;
39
44
  onKeyboardMoveInteractive?: DirectEventHandler<KeyboardMoveEvent>;
45
+ /// focused input
40
46
  onFocusedInputLayoutChanged?: DirectEventHandler<FocusedInputLayoutChangedEvent>;
47
+ onFocusedInputTextChanged?: DirectEventHandler<FocusedInputTextChangedEvent>;
41
48
  }
42
49
 
43
50
  export default codegenNativeComponent<NativeProps>(
@@ -8,6 +8,7 @@ export interface Spec extends TurboModule {
8
8
  // methods
9
9
  setInputMode(mode: number): void;
10
10
  setDefaultMode(): void;
11
+ dismiss(): void;
11
12
 
12
13
  // event emitter
13
14
  addListener: (eventName: string) => void;
package/src/types.ts CHANGED
@@ -22,13 +22,16 @@ export type FocusedInputLayoutChangedEvent = {
22
22
  absoluteY: number;
23
23
  };
24
24
  };
25
+ export type FocusedInputTextChangedEvent = {
26
+ text: string;
27
+ };
25
28
  export type EventWithName<T> = {
26
29
  eventName: string;
27
30
  } & T;
28
31
 
29
32
  // native View/Module declarations
30
33
  export type KeyboardControllerProps = {
31
- enabled?: boolean;
34
+ // callback props
32
35
  onKeyboardMoveStart?: (
33
36
  e: NativeSyntheticEvent<EventWithName<NativeEvent>>
34
37
  ) => void;
@@ -44,6 +47,9 @@ export type KeyboardControllerProps = {
44
47
  onFocusedInputLayoutChanged?: (
45
48
  e: NativeSyntheticEvent<EventWithName<FocusedInputLayoutChangedEvent>>
46
49
  ) => void;
50
+ onFocusedInputTextChanged?: (
51
+ e: NativeSyntheticEvent<EventWithName<FocusedInputTextChangedEvent>>
52
+ ) => void;
47
53
  // fake props used to activate reanimated bindings
48
54
  onKeyboardMoveReanimated?: (
49
55
  e: NativeSyntheticEvent<EventWithName<NativeEvent>>
@@ -51,8 +57,13 @@ export type KeyboardControllerProps = {
51
57
  onFocusedInputLayoutChangedReanimated?: (
52
58
  e: NativeSyntheticEvent<EventWithName<FocusedInputLayoutChangedEvent>>
53
59
  ) => void;
60
+ onFocusedInputTextChangedReanimated?: (
61
+ e: NativeSyntheticEvent<EventWithName<FocusedInputTextChangedEvent>>
62
+ ) => void;
63
+ // props
54
64
  statusBarTranslucent?: boolean;
55
65
  navigationBarTranslucent?: boolean;
66
+ enabled?: boolean;
56
67
  } & ViewProps;
57
68
 
58
69
  export type KeyboardGestureAreaProps = {
@@ -74,6 +85,8 @@ export type KeyboardControllerModule = {
74
85
  // android only
75
86
  setDefaultMode: () => void;
76
87
  setInputMode: (mode: number) => void;
88
+ // all platforms
89
+ dismiss: () => void;
77
90
  // native event module stuff
78
91
  addListener: (eventName: string) => void;
79
92
  removeListeners: (count: number) => void;
@@ -108,7 +121,7 @@ export type KeyboardHandlerHook<TContext, Event> = (
108
121
  },
109
122
  dependencies?: unknown[]
110
123
  ) => (e: NativeSyntheticEvent<Event>) => void;
111
- export type FocusedInputHandlerHook<TContext, Event> = (
124
+ export type FocusedInputLayoutHandlerHook<TContext, Event> = (
112
125
  handlers: {
113
126
  onFocusedInputLayoutChanged?: (
114
127
  e: FocusedInputLayoutChangedEvent,
@@ -117,6 +130,15 @@ export type FocusedInputHandlerHook<TContext, Event> = (
117
130
  },
118
131
  dependencies?: unknown[]
119
132
  ) => (e: NativeSyntheticEvent<Event>) => void;
133
+ export type FocusedInputTextHandlerHook<TContext, Event> = (
134
+ handlers: {
135
+ onFocusedInputTextChanged?: (
136
+ e: FocusedInputTextChangedEvent,
137
+ context: TContext
138
+ ) => void;
139
+ },
140
+ dependencies?: unknown[]
141
+ ) => (e: NativeSyntheticEvent<Event>) => void;
120
142
 
121
143
  // package types
122
144
  export type Handlers<T> = Record<string, T | undefined>;
@@ -127,3 +149,7 @@ export type KeyboardHandler = Partial<{
127
149
  onInteractive: (e: NativeEvent) => void;
128
150
  }>;
129
151
  export type KeyboardHandlers = Handlers<KeyboardHandler>;
152
+ export type FocusedInputHandler = Partial<{
153
+ onChangeText: (e: FocusedInputTextChangedEvent) => void;
154
+ }>;
155
+ export type FocusedInputHandlers = Handlers<FocusedInputHandler>;