react-native-keyboard-controller 1.14.4 → 1.15.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 (95) hide show
  1. package/android/build.gradle +3 -2
  2. package/android/gradle.properties +1 -0
  3. package/android/react-native-helpers.gradle +5 -11
  4. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +2 -2
  5. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt +35 -0
  6. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt +18 -0
  7. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +5 -0
  8. package/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt +9 -6
  9. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +13 -4
  10. package/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/JSPointerDispatcherCompat.kt +56 -0
  11. package/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardViewGroup.kt +10 -7
  12. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +2 -2
  13. package/ios/KeyboardControllerModule.mm +3 -3
  14. package/ios/KeyboardControllerModuleImpl.swift +66 -0
  15. package/ios/events/KeyboardEventEmitterPayload.swift +23 -0
  16. package/ios/extensions/Notification.swift +17 -0
  17. package/ios/extensions/UIKeyboardAppearance.swift +21 -0
  18. package/ios/extensions/UIKeyboardType.swift +30 -0
  19. package/ios/observers/KeyboardMovementObserver.swift +8 -27
  20. package/ios/{traversal → protocols}/TextInput.swift +5 -1
  21. package/ios/traversal/ViewHierarchyNavigator.swift +4 -1
  22. package/jest/index.js +20 -15
  23. package/lib/commonjs/animated.js +6 -0
  24. package/lib/commonjs/animated.js.map +1 -1
  25. package/lib/commonjs/bindings.js +2 -2
  26. package/lib/commonjs/bindings.js.map +1 -1
  27. package/lib/commonjs/bindings.native.js +4 -3
  28. package/lib/commonjs/bindings.native.js.map +1 -1
  29. package/lib/commonjs/components/KeyboardAvoidingView/index.js.map +1 -1
  30. package/lib/commonjs/components/KeyboardStickyView/index.js +3 -2
  31. package/lib/commonjs/components/KeyboardStickyView/index.js.map +1 -1
  32. package/lib/commonjs/components/KeyboardToolbar/index.js +14 -9
  33. package/lib/commonjs/components/KeyboardToolbar/index.js.map +1 -1
  34. package/lib/commonjs/hooks/index.js +3 -3
  35. package/lib/commonjs/hooks/index.js.map +1 -1
  36. package/lib/commonjs/hooks/useWindowDimensions/index.android.js +5 -0
  37. package/lib/commonjs/hooks/useWindowDimensions/index.android.js.map +1 -1
  38. package/lib/commonjs/index.js +12 -0
  39. package/lib/commonjs/index.js.map +1 -1
  40. package/lib/commonjs/internal.js +2 -2
  41. package/lib/commonjs/internal.js.map +1 -1
  42. package/lib/commonjs/module.js +45 -0
  43. package/lib/commonjs/module.js.map +1 -0
  44. package/lib/commonjs/specs/NativeKeyboardController.js.map +1 -1
  45. package/lib/commonjs/types.js.map +1 -1
  46. package/lib/module/animated.js +6 -0
  47. package/lib/module/animated.js.map +1 -1
  48. package/lib/module/bindings.js +1 -1
  49. package/lib/module/bindings.js.map +1 -1
  50. package/lib/module/bindings.native.js +3 -2
  51. package/lib/module/bindings.native.js.map +1 -1
  52. package/lib/module/components/KeyboardAvoidingView/index.js.map +1 -1
  53. package/lib/module/components/KeyboardStickyView/index.js +3 -2
  54. package/lib/module/components/KeyboardStickyView/index.js.map +1 -1
  55. package/lib/module/components/KeyboardToolbar/index.js +15 -10
  56. package/lib/module/components/KeyboardToolbar/index.js.map +1 -1
  57. package/lib/module/hooks/index.js +1 -1
  58. package/lib/module/hooks/index.js.map +1 -1
  59. package/lib/module/hooks/useWindowDimensions/index.android.js +5 -0
  60. package/lib/module/hooks/useWindowDimensions/index.android.js.map +1 -1
  61. package/lib/module/index.js +1 -0
  62. package/lib/module/index.js.map +1 -1
  63. package/lib/module/internal.js +2 -2
  64. package/lib/module/internal.js.map +1 -1
  65. package/lib/module/module.js +39 -0
  66. package/lib/module/module.js.map +1 -0
  67. package/lib/module/specs/NativeKeyboardController.js.map +1 -1
  68. package/lib/module/types.js.map +1 -1
  69. package/lib/typescript/bindings.d.ts +5 -6
  70. package/lib/typescript/bindings.native.d.ts +2 -3
  71. package/lib/typescript/components/KeyboardAvoidingView/index.d.ts +14 -24
  72. package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +6 -6
  73. package/lib/typescript/components/KeyboardAwareScrollView/utils.d.ts +1 -1
  74. package/lib/typescript/components/KeyboardStickyView/index.d.ts +8 -4
  75. package/lib/typescript/components/KeyboardToolbar/Button.d.ts +2 -1
  76. package/lib/typescript/components/KeyboardToolbar/index.d.ts +2 -1
  77. package/lib/typescript/index.d.ts +1 -0
  78. package/lib/typescript/internal.d.ts +0 -1
  79. package/lib/typescript/module.d.ts +2 -0
  80. package/lib/typescript/specs/NativeKeyboardController.d.ts +1 -1
  81. package/lib/typescript/types.d.ts +15 -2
  82. package/package.json +6 -4
  83. package/src/animated.tsx +6 -0
  84. package/src/bindings.native.ts +5 -4
  85. package/src/bindings.ts +2 -2
  86. package/src/components/KeyboardAvoidingView/index.tsx +27 -11
  87. package/src/components/KeyboardStickyView/index.tsx +12 -3
  88. package/src/components/KeyboardToolbar/index.tsx +14 -11
  89. package/src/hooks/index.ts +1 -1
  90. package/src/hooks/useWindowDimensions/index.android.ts +5 -0
  91. package/src/index.ts +1 -0
  92. package/src/internal.ts +2 -2
  93. package/src/module.ts +50 -0
  94. package/src/specs/NativeKeyboardController.ts +1 -1
  95. package/src/types.ts +17 -1
@@ -1,7 +1,8 @@
1
1
  import React, { useCallback, useEffect, useMemo, useState } from "react";
2
2
  import { StyleSheet, Text, View } from "react-native";
3
3
 
4
- import { FocusedInputEvents, KeyboardController } from "../../bindings";
4
+ import { FocusedInputEvents } from "../../bindings";
5
+ import { KeyboardController } from "../../module";
5
6
  import useColorScheme from "../hooks/useColorScheme";
6
7
  import KeyboardStickyView from "../KeyboardStickyView";
7
8
 
@@ -10,6 +11,7 @@ import Button from "./Button";
10
11
  import { colors } from "./colors";
11
12
 
12
13
  import type { HEX, KeyboardToolbarTheme } from "./types";
14
+ import type { KeyboardStickyViewProps } from "../KeyboardStickyView";
13
15
  import type { ReactNode } from "react";
14
16
  import type { GestureResponderEvent, ViewProps } from "react-native";
15
17
 
@@ -52,7 +54,7 @@ export type KeyboardToolbarProps = Omit<
52
54
  * A value for container opacity in hexadecimal format (e.g. `ff`). Default value is `ff`.
53
55
  */
54
56
  opacity?: HEX;
55
- };
57
+ } & Pick<KeyboardStickyViewProps, "offset" | "enabled">;
56
58
 
57
59
  const TEST_ID_KEYBOARD_TOOLBAR = "keyboard.toolbar";
58
60
  const TEST_ID_KEYBOARD_TOOLBAR_PREVIOUS = `${TEST_ID_KEYBOARD_TOOLBAR}.previous`;
@@ -62,11 +64,6 @@ const TEST_ID_KEYBOARD_TOOLBAR_DONE = `${TEST_ID_KEYBOARD_TOOLBAR}.done`;
62
64
 
63
65
  const KEYBOARD_TOOLBAR_HEIGHT = 42;
64
66
  const DEFAULT_OPACITY: HEX = "FF";
65
- const offset = { closed: KEYBOARD_TOOLBAR_HEIGHT };
66
-
67
- const dismissKeyboard = () => KeyboardController.dismiss();
68
- const goToNextField = () => KeyboardController.setFocusTo("next");
69
- const goToPrevField = () => KeyboardController.setFocusTo("prev");
70
67
 
71
68
  /**
72
69
  * `KeyboardToolbar` is a component that is shown above the keyboard with `Prev`/`Next` and
@@ -84,6 +81,8 @@ const KeyboardToolbar: React.FC<KeyboardToolbarProps> = ({
84
81
  onDoneCallback,
85
82
  blur = null,
86
83
  opacity = DEFAULT_OPACITY,
84
+ offset: { closed = 0, opened = 0 } = {},
85
+ enabled = true,
87
86
  ...rest
88
87
  }) => {
89
88
  const colorScheme = useColorScheme();
@@ -114,6 +113,10 @@ const KeyboardToolbar: React.FC<KeyboardToolbarProps> = ({
114
113
  ],
115
114
  [colorScheme, opacity, theme],
116
115
  );
116
+ const offset = useMemo(
117
+ () => ({ closed: closed + KEYBOARD_TOOLBAR_HEIGHT, opened }),
118
+ [closed, opened],
119
+ );
117
120
  const ButtonContainer = button || Button;
118
121
  const IconContainer = icon || Arrow;
119
122
 
@@ -122,7 +125,7 @@ const KeyboardToolbar: React.FC<KeyboardToolbarProps> = ({
122
125
  onNextCallback?.(event);
123
126
 
124
127
  if (!event.isDefaultPrevented()) {
125
- goToNextField();
128
+ KeyboardController.setFocusTo("next");
126
129
  }
127
130
  },
128
131
  [onNextCallback],
@@ -132,7 +135,7 @@ const KeyboardToolbar: React.FC<KeyboardToolbarProps> = ({
132
135
  onPrevCallback?.(event);
133
136
 
134
137
  if (!event.isDefaultPrevented()) {
135
- goToPrevField();
138
+ KeyboardController.setFocusTo("prev");
136
139
  }
137
140
  },
138
141
  [onPrevCallback],
@@ -142,14 +145,14 @@ const KeyboardToolbar: React.FC<KeyboardToolbarProps> = ({
142
145
  onDoneCallback?.(event);
143
146
 
144
147
  if (!event.isDefaultPrevented()) {
145
- dismissKeyboard();
148
+ KeyboardController.dismiss();
146
149
  }
147
150
  },
148
151
  [onDoneCallback],
149
152
  );
150
153
 
151
154
  return (
152
- <KeyboardStickyView offset={offset}>
155
+ <KeyboardStickyView enabled={enabled} offset={offset}>
153
156
  <View {...rest} style={toolbarStyle} testID={TEST_ID_KEYBOARD_TOOLBAR}>
154
157
  {blur}
155
158
  {showArrows && (
@@ -1,8 +1,8 @@
1
1
  import { useEffect, useLayoutEffect } from "react";
2
2
 
3
- import { KeyboardController } from "../bindings";
4
3
  import { AndroidSoftInputModes } from "../constants";
5
4
  import { useKeyboardContext } from "../context";
5
+ import { KeyboardController } from "../module";
6
6
 
7
7
  import type { AnimatedContext, ReanimatedContext } from "../context";
8
8
  import type { FocusedInputHandler, KeyboardHandler } from "../types";
@@ -24,6 +24,11 @@ export const useWindowDimensions = () => {
24
24
  },
25
25
  );
26
26
 
27
+ // we might have missed an update between reading a value in render and
28
+ // `addListener` in this handler, so we set it here. If there was
29
+ // no change, React will filter out this update as a no-op.
30
+ setDimensions(initialDimensions);
31
+
27
32
  return () => {
28
33
  subscription.remove();
29
34
  };
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ export * from "./animated";
3
3
  export * from "./context";
4
4
  export * from "./hooks";
5
5
  export * from "./constants";
6
+ export * from "./module";
6
7
  export * from "./types";
7
8
 
8
9
  export {
package/src/internal.ts CHANGED
@@ -48,8 +48,8 @@ export function useEventHandlerRegistration<
48
48
  if (viewTagRef.current) {
49
49
  attachWorkletHandlers();
50
50
  } else {
51
- // view may not be mounted yet - defer registration to next event loop
52
- setImmediate(attachWorkletHandlers);
51
+ // view may not be mounted yet - defer registration until call-stack becomes empty
52
+ queueMicrotask(attachWorkletHandlers);
53
53
  }
54
54
 
55
55
  return () => {
package/src/module.ts ADDED
@@ -0,0 +1,50 @@
1
+ import { KeyboardControllerNative, KeyboardEvents } from "./bindings";
2
+
3
+ import type {
4
+ DismissOptions,
5
+ KeyboardControllerModule,
6
+ KeyboardEventData,
7
+ } from "./types";
8
+
9
+ let isClosed = false;
10
+ let lastEvent: KeyboardEventData | null = null;
11
+
12
+ KeyboardEvents.addListener("keyboardDidHide", (e) => {
13
+ isClosed = true;
14
+ lastEvent = e;
15
+ });
16
+
17
+ KeyboardEvents.addListener("keyboardDidShow", (e) => {
18
+ isClosed = false;
19
+ lastEvent = e;
20
+ });
21
+
22
+ const dismiss = async (
23
+ { keepFocus }: DismissOptions = { keepFocus: false },
24
+ ): Promise<void> => {
25
+ return new Promise((resolve) => {
26
+ if (isClosed) {
27
+ resolve();
28
+
29
+ return;
30
+ }
31
+
32
+ const subscription = KeyboardEvents.addListener("keyboardDidHide", () => {
33
+ resolve(undefined);
34
+ subscription.remove();
35
+ });
36
+
37
+ KeyboardControllerNative.dismiss(keepFocus);
38
+ });
39
+ };
40
+ const isVisible = () => !isClosed;
41
+ const state = () => lastEvent;
42
+
43
+ export const KeyboardController: KeyboardControllerModule = {
44
+ setDefaultMode: KeyboardControllerNative.setDefaultMode,
45
+ setInputMode: KeyboardControllerNative.setInputMode,
46
+ setFocusTo: KeyboardControllerNative.setFocusTo,
47
+ dismiss,
48
+ isVisible,
49
+ state,
50
+ };
@@ -8,7 +8,7 @@ export interface Spec extends TurboModule {
8
8
  // methods
9
9
  setInputMode(mode: number): void;
10
10
  setDefaultMode(): void;
11
- dismiss(): void;
11
+ dismiss(keepFocus: boolean): void;
12
12
  setFocusTo(direction: string): void;
13
13
 
14
14
  // event emitter
package/src/types.ts CHANGED
@@ -2,6 +2,7 @@ import type { PropsWithChildren } from "react";
2
2
  import type {
3
3
  EmitterSubscription,
4
4
  NativeSyntheticEvent,
5
+ TextInputProps,
5
6
  ViewProps,
6
7
  } from "react-native";
7
8
 
@@ -114,12 +115,25 @@ export type OverKeyboardViewProps = PropsWithChildren<{
114
115
  }>;
115
116
 
116
117
  export type Direction = "next" | "prev" | "current";
118
+ export type DismissOptions = {
119
+ keepFocus: boolean;
120
+ };
117
121
  export type KeyboardControllerModule = {
118
122
  // android only
119
123
  setDefaultMode: () => void;
120
124
  setInputMode: (mode: number) => void;
121
125
  // all platforms
122
- dismiss: () => void;
126
+ dismiss: (options?: DismissOptions) => Promise<void>;
127
+ setFocusTo: (direction: Direction) => void;
128
+ isVisible: () => boolean;
129
+ state: () => KeyboardEventData | null;
130
+ };
131
+ export type KeyboardControllerNativeModule = {
132
+ // android only
133
+ setDefaultMode: () => void;
134
+ setInputMode: (mode: number) => void;
135
+ // all platforms
136
+ dismiss: (keepFocus: boolean) => void;
123
137
  setFocusTo: (direction: Direction) => void;
124
138
  // native event module stuff
125
139
  addListener: (eventName: string) => void;
@@ -137,6 +151,8 @@ export type KeyboardEventData = {
137
151
  duration: number;
138
152
  timestamp: number;
139
153
  target: number;
154
+ type: NonNullable<TextInputProps["keyboardType"]>;
155
+ appearance: NonNullable<TextInputProps["keyboardAppearance"]>;
140
156
  };
141
157
  export type KeyboardEventsModule = {
142
158
  addListener: (