react-native-keyboard-controller 1.21.0-beta.3 → 1.21.1
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/base/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +1 -0
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/ClippingScrollViewDecoratorViewManager.kt +7 -0
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +8 -0
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardToolbarGroupViewManager.kt +23 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +12 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt +2 -1
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt +5 -1
- package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardToolbarGroupViewManagerImpl.kt +13 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt +4 -6
- package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +26 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt +31 -4
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/ClippingScrollViewDecoratorView.kt +5 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardToolbarGroupReactViewGroup.kt +13 -0
- package/android/src/main/jni/RNKC.h +2 -0
- package/android/src/paper/java/com/reactnativekeyboardcontroller/ClippingScrollViewDecoratorViewManager.kt +8 -0
- package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +9 -0
- package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardToolbarGroupViewManager.kt +15 -0
- package/android/src/turbo/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +2 -0
- package/common/cpp/react/renderer/components/RNKC/RNKCClippingScrollViewDecoratorViewComponentDescriptor.h +27 -0
- package/common/cpp/react/renderer/components/RNKC/RNKCClippingScrollViewDecoratorViewShadowNode.cpp +14 -0
- package/common/cpp/react/renderer/components/RNKC/RNKCClippingScrollViewDecoratorViewShadowNode.h +30 -0
- package/common/cpp/react/renderer/components/RNKC/RNKCClippingScrollViewDecoratorViewState.h +28 -0
- package/common/cpp/react/renderer/components/RNKC/RNKCKeyboardToolbarGroupViewComponentDescriptor.h +20 -0
- package/common/cpp/react/renderer/components/RNKC/RNKCKeyboardToolbarGroupViewShadowNode.cpp +7 -0
- package/common/cpp/react/renderer/components/RNKC/RNKCKeyboardToolbarGroupViewShadowNode.h +23 -0
- package/common/cpp/react/renderer/components/RNKC/RNKCKeyboardToolbarGroupViewState.h +21 -0
- package/ios/KeyboardControllerModule.mm +36 -0
- package/ios/extensions/UIApplication.swift +1 -1
- package/ios/observers/FocusedInputObserver.swift +2 -1
- package/ios/traversal/ViewHierarchyNavigator.swift +49 -3
- package/ios/views/ClippingScrollViewDecoratorViewManager.h +26 -0
- package/ios/views/ClippingScrollViewDecoratorViewManager.mm +231 -0
- package/ios/views/KeyboardToolbarGroupViewManager.h +28 -0
- package/ios/views/KeyboardToolbarGroupViewManager.mm +88 -0
- package/jest/index.js +11 -1
- package/lib/commonjs/bindings.js +18 -2
- package/lib/commonjs/bindings.js.map +1 -1
- package/lib/commonjs/bindings.native.js +3 -4
- package/lib/commonjs/bindings.native.js.map +1 -1
- package/lib/commonjs/components/KeyboardAvoidingView/index.js +30 -4
- package/lib/commonjs/components/KeyboardAvoidingView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js +17 -4
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardChatScrollView/index.js +33 -2
- package/lib/commonjs/components/KeyboardChatScrollView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardChatScrollView/types.js.map +1 -1
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/helpers.js +107 -21
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/helpers.js.map +1 -1
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js +45 -17
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js.map +1 -1
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.js +61 -26
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/types.js.map +1 -1
- package/lib/commonjs/components/KeyboardChatScrollView/useExtraContentPadding/index.js +72 -0
- package/lib/commonjs/components/KeyboardChatScrollView/useExtraContentPadding/index.js.map +1 -0
- package/lib/commonjs/components/KeyboardToolbar/index.js +1 -0
- package/lib/commonjs/components/KeyboardToolbar/index.js.map +1 -1
- package/lib/commonjs/components/ScrollViewWithBottomPadding/index.js +18 -6
- package/lib/commonjs/components/ScrollViewWithBottomPadding/index.js.map +1 -1
- package/lib/commonjs/specs/ClippingScrollViewDecoratorViewNativeComponent.js +1 -2
- package/lib/commonjs/specs/ClippingScrollViewDecoratorViewNativeComponent.js.map +1 -1
- package/lib/commonjs/specs/KeyboardToolbarGroupViewNativeComponent.js +12 -0
- package/lib/commonjs/specs/KeyboardToolbarGroupViewNativeComponent.js.map +1 -0
- package/lib/commonjs/specs/NativeKeyboardController.js.map +1 -1
- package/lib/commonjs/types/module.js.map +1 -1
- package/lib/commonjs/types/views.js.map +1 -1
- package/lib/module/bindings.js +17 -1
- package/lib/module/bindings.js.map +1 -1
- package/lib/module/bindings.native.js +2 -3
- package/lib/module/bindings.native.js.map +1 -1
- package/lib/module/components/KeyboardAvoidingView/index.js +29 -4
- package/lib/module/components/KeyboardAvoidingView/index.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/index.js +17 -4
- package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/module/components/KeyboardChatScrollView/index.js +34 -3
- package/lib/module/components/KeyboardChatScrollView/index.js.map +1 -1
- package/lib/module/components/KeyboardChatScrollView/types.js.map +1 -1
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/helpers.js +98 -16
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/helpers.js.map +1 -1
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js +46 -18
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js.map +1 -1
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.js +62 -27
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.js.map +1 -1
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/types.js.map +1 -1
- package/lib/module/components/KeyboardChatScrollView/useExtraContentPadding/index.js +67 -0
- package/lib/module/components/KeyboardChatScrollView/useExtraContentPadding/index.js.map +1 -0
- package/lib/module/components/KeyboardToolbar/index.js +2 -1
- package/lib/module/components/KeyboardToolbar/index.js.map +1 -1
- package/lib/module/components/ScrollViewWithBottomPadding/index.js +19 -7
- package/lib/module/components/ScrollViewWithBottomPadding/index.js.map +1 -1
- package/lib/module/specs/ClippingScrollViewDecoratorViewNativeComponent.js +1 -2
- package/lib/module/specs/ClippingScrollViewDecoratorViewNativeComponent.js.map +1 -1
- package/lib/module/specs/KeyboardToolbarGroupViewNativeComponent.js +5 -0
- package/lib/module/specs/KeyboardToolbarGroupViewNativeComponent.js.map +1 -0
- package/lib/module/specs/NativeKeyboardController.js.map +1 -1
- package/lib/module/types/module.js.map +1 -1
- package/lib/module/types/views.js.map +1 -1
- package/lib/typescript/bindings.d.ts +12 -2
- package/lib/typescript/bindings.native.d.ts +2 -1
- package/lib/typescript/components/KeyboardAvoidingView/index.d.ts +44 -13
- package/lib/typescript/components/KeyboardChatScrollView/index.d.ts +3 -0
- package/lib/typescript/components/KeyboardChatScrollView/types.d.ts +41 -0
- package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/helpers.d.ts +63 -8
- package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/index.d.ts +1 -4
- package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/types.d.ts +15 -0
- package/lib/typescript/components/KeyboardChatScrollView/useExtraContentPadding/index.d.ts +43 -0
- package/lib/typescript/components/KeyboardToolbar/index.d.ts +2 -0
- package/lib/typescript/components/ScrollViewWithBottomPadding/index.d.ts +3 -0
- package/lib/typescript/specs/ClippingScrollViewDecoratorViewNativeComponent.d.ts +1 -0
- package/lib/typescript/specs/KeyboardToolbarGroupViewNativeComponent.d.ts +6 -0
- package/lib/typescript/specs/NativeKeyboardController.d.ts +1 -0
- package/lib/typescript/types/module.d.ts +7 -0
- package/lib/typescript/types/views.d.ts +2 -0
- package/package.json +6 -2
- package/react-native.config.js +2 -0
- package/src/bindings.native.ts +4 -4
- package/src/bindings.ts +15 -1
- package/src/components/KeyboardAvoidingView/index.tsx +56 -29
- package/src/components/KeyboardAwareScrollView/index.tsx +20 -5
- package/src/components/KeyboardChatScrollView/index.tsx +47 -3
- package/src/components/KeyboardChatScrollView/types.ts +41 -0
- package/src/components/KeyboardChatScrollView/useChatKeyboard/helpers.ts +126 -21
- package/src/components/KeyboardChatScrollView/useChatKeyboard/index.ios.ts +101 -21
- package/src/components/KeyboardChatScrollView/useChatKeyboard/index.ts +116 -40
- package/src/components/KeyboardChatScrollView/useChatKeyboard/types.ts +9 -0
- package/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts +123 -0
- package/src/components/KeyboardToolbar/index.tsx +6 -1
- package/src/components/ScrollViewWithBottomPadding/index.tsx +31 -4
- package/src/specs/ClippingScrollViewDecoratorViewNativeComponent.ts +1 -1
- package/src/specs/KeyboardToolbarGroupViewNativeComponent.ts +10 -0
- package/src/specs/NativeKeyboardController.ts +1 -0
- package/src/types/module.ts +9 -0
- package/src/types/views.ts +2 -0
- package/android/.settings/org.eclipse.buildship.core.prefs +0 -2
- package/ios/KeyboardController.xcodeproj/xcuserdata/kirylziusko.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/ios/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/ios/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/ios/Tests/Tests.xcodeproj/project.xcworkspace/xcuserdata/kirylziusko.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/Tests/Tests.xcodeproj/xcuserdata/kirylziusko.xcuserdatad/xcschemes/xcschememanagement.plist +0 -32
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AnimatedScrollViewComponent } from "../ScrollViewWithBottomPadding";
|
|
2
2
|
import type { KeyboardLiftBehavior } from "./useChatKeyboard/types";
|
|
3
3
|
import type { ScrollViewProps } from "react-native";
|
|
4
|
+
import type { SharedValue } from "react-native-reanimated";
|
|
4
5
|
export type KeyboardChatScrollViewProps = {
|
|
5
6
|
/** Custom component for `ScrollView`. Default is `ScrollView`. */
|
|
6
7
|
ScrollViewComponent?: AnimatedScrollViewComponent;
|
|
@@ -45,4 +46,44 @@ export type KeyboardChatScrollViewProps = {
|
|
|
45
46
|
* Default is `false`.
|
|
46
47
|
*/
|
|
47
48
|
freeze?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* A shared value representing additional padding from external elements
|
|
51
|
+
* (e.g., a growing multiline `TextInput` in a `KeyboardStickyView`).
|
|
52
|
+
*
|
|
53
|
+
* When this value changes:
|
|
54
|
+
* - The scrollable range is always extended/contracted (via `contentInset`).
|
|
55
|
+
* - The scroll position is conditionally adjusted based on `keyboardLiftBehavior`.
|
|
56
|
+
*
|
|
57
|
+
* Default is `undefined` (no extra padding).
|
|
58
|
+
*/
|
|
59
|
+
extraContentPadding?: SharedValue<number>;
|
|
60
|
+
/**
|
|
61
|
+
* When `true`, applies a runtime workaround for a React Native 0.81+ bug
|
|
62
|
+
* where the ScrollView's `contentInset` area does not respond to touch/scroll
|
|
63
|
+
* gestures (facebook/react-native#54123).
|
|
64
|
+
*
|
|
65
|
+
* This uses Objective-C runtime method swizzling on the ScrollView's container
|
|
66
|
+
* view, which is inherently fragile. Only enable if you are affected by the
|
|
67
|
+
* upstream bug and understand the risks.
|
|
68
|
+
*
|
|
69
|
+
* iOS only. Default is `false`.
|
|
70
|
+
*/
|
|
71
|
+
applyWorkaroundForContentInsetHitTestBug?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* A shared value representing a minimum inset floor (in pixels).
|
|
74
|
+
*
|
|
75
|
+
* When set, the total bottom padding is computed as:
|
|
76
|
+
* `max(blankSpace, keyboardPadding + extraContentPadding)`
|
|
77
|
+
*
|
|
78
|
+
* This means the keyboard "absorbs" into the minimum padding rather than adding to it:
|
|
79
|
+
* - When `blankSpace >= keyboard + extraContentPadding`: content does NOT move on keyboard open/close.
|
|
80
|
+
* - When `blankSpace < keyboard + extraContentPadding`: content moves, but only by the excess amount.
|
|
81
|
+
*
|
|
82
|
+
* Useful in AI chat apps where a sent message needs space below it (to push it to the top
|
|
83
|
+
* of the viewport) while the AI response streams in, without that space causing extra movement
|
|
84
|
+
* when the keyboard opens.
|
|
85
|
+
*
|
|
86
|
+
* Default is `undefined` (equivalent to `0` — no minimum floor).
|
|
87
|
+
*/
|
|
88
|
+
blankSpace?: SharedValue<number>;
|
|
48
89
|
} & ScrollViewProps;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { KeyboardLiftBehavior } from "./types";
|
|
2
2
|
/**
|
|
3
3
|
* Map the current keyboard height to an effective height that accounts for a
|
|
4
|
-
* fixed offset (e.g.
|
|
4
|
+
* fixed offset (e.g. Bottom safe-area or tab-bar height)..
|
|
5
5
|
*
|
|
6
6
|
* @param height - Current keyboard height.
|
|
7
7
|
* @param targetKeyboardHeight - Full target keyboard height (captured on keyboard open).
|
|
@@ -13,7 +13,7 @@ import type { KeyboardLiftBehavior } from "./types";
|
|
|
13
13
|
* getEffectiveHeight(150, 300, 50); // 125
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
-
export declare
|
|
16
|
+
export declare const getEffectiveHeight: (height: number, targetKeyboardHeight: number, offset: number) => number;
|
|
17
17
|
/**
|
|
18
18
|
* Check whether the scroll view is at the end of its content.
|
|
19
19
|
*
|
|
@@ -32,7 +32,7 @@ export declare function getEffectiveHeight(height: number, targetKeyboardHeight:
|
|
|
32
32
|
* const atEndInverted = isScrollAtEnd(5, 800, 2000, true); // true (5 <= 20)
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
|
-
export declare
|
|
35
|
+
export declare const isScrollAtEnd: (scrollOffset: number, layoutHeight: number, contentHeight: number, inverted?: boolean) => boolean;
|
|
36
36
|
/**
|
|
37
37
|
* Decide whether content should be shifted based on the keyboard lift behavior.
|
|
38
38
|
*
|
|
@@ -45,33 +45,88 @@ export declare function isScrollAtEnd(scrollOffset: number, layoutHeight: number
|
|
|
45
45
|
* shouldShiftContent("whenAtEnd", false); // false
|
|
46
46
|
* ```
|
|
47
47
|
*/
|
|
48
|
-
export declare
|
|
48
|
+
export declare const shouldShiftContent: (behavior: KeyboardLiftBehavior, isAtEnd: boolean) => boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Compute the fraction of minimum padding space currently visible in the viewport (0–1).
|
|
51
|
+
*
|
|
52
|
+
* The minimum padding space lives in the scroll view's contentInset, NOT in the
|
|
53
|
+
* content itself. So `contentHeight` (from onContentSizeChange / scroll
|
|
54
|
+
* events) does **not** include it. The visible portion is how far the
|
|
55
|
+
* viewport extends past the content boundary into the inset area.
|
|
56
|
+
*
|
|
57
|
+
* For non-inverted lists the padding is in contentInset.bottom.
|
|
58
|
+
* For inverted lists the padding is in contentInset.top (negative scroll).
|
|
59
|
+
*
|
|
60
|
+
* @param scrollOffset - Current vertical scroll offset.
|
|
61
|
+
* @param layoutHeight - Visible height of the scroll view.
|
|
62
|
+
* @param contentHeight - Height of the scroll content (excludes insets).
|
|
63
|
+
* @param blankSpace - Size of the minimum padding inset area.
|
|
64
|
+
* @param inverted - Whether the list is inverted.
|
|
65
|
+
* @returns A value between 0 (padding fully off-screen) and 1 (padding fully visible).
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* // Non-inverted: contentHeight=1500, layout=800, blankSpace=300
|
|
69
|
+
* getVisibleMinimumPaddingFraction(1500, 800, 1500, 300, false); // 1 (at end, viewport past content)
|
|
70
|
+
* getVisibleMinimumPaddingFraction(850, 800, 1500, 300, false); // 0.5 (half padding visible)
|
|
71
|
+
* getVisibleMinimumPaddingFraction(700, 800, 1500, 300, false); // 0 (padding off-screen)
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare const getVisibleMinimumPaddingFraction: (scrollOffset: number, layoutHeight: number, contentHeight: number, blankSpace: number, inverted: boolean) => number;
|
|
75
|
+
/**
|
|
76
|
+
* Compute how much of the minimum content padding absorbs the keyboard + extraContentPadding.
|
|
77
|
+
*
|
|
78
|
+
* @param blankSpace - Minimum inset floor.
|
|
79
|
+
* @param extraContentPadding - Extra content padding from external elements.
|
|
80
|
+
* @returns The portion of blankSpace that absorbs keyboard displacement.
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* getMinimumPaddingAbsorbed(500, 20); // 480
|
|
84
|
+
* getMinimumPaddingAbsorbed(0, 20); // 0
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare const getMinimumPaddingAbsorbed: (blankSpace: number, extraContentPadding: number) => number;
|
|
88
|
+
/**
|
|
89
|
+
* Compute the effective scroll displacement after minimum padding absorption.
|
|
90
|
+
*
|
|
91
|
+
* @param rawEffective - Raw effective keyboard height.
|
|
92
|
+
* @param minimumPaddingAbsorbed - Amount absorbed by minimum content padding.
|
|
93
|
+
* @returns The scroll displacement after subtracting the absorbed portion.
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* getScrollEffective(300, 200); // 100
|
|
97
|
+
* getScrollEffective(300, 400); // 0
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export declare const getScrollEffective: (rawEffective: number, minimumPaddingAbsorbed: number) => number;
|
|
49
101
|
/**
|
|
50
102
|
* Compute the clamped scroll target for non-inverted lists.
|
|
51
103
|
*
|
|
52
104
|
* @param offsetBeforeScroll - Scroll position before keyboard appeared.
|
|
53
|
-
* @param keyboardHeight - Current keyboard height.
|
|
105
|
+
* @param keyboardHeight - Current keyboard height (used for scroll displacement).
|
|
54
106
|
* @param contentHeight - Total height of the scrollable content.
|
|
55
107
|
* @param layoutHeight - Visible height of the scroll view.
|
|
108
|
+
* @param totalPaddingForMaxScroll - Total padding to use for maxScroll calculation. When provided, used instead of keyboardHeight for the scrollable range. Defaults to keyboardHeight.
|
|
56
109
|
* @returns Clamped scroll target between 0 and maxScroll.
|
|
57
110
|
* @example
|
|
58
111
|
* ```ts
|
|
59
112
|
* clampedScrollTarget(100, 300, 1000, 800); // 400
|
|
113
|
+
* clampedScrollTarget(100, 100, 1000, 800, 500); // 200, maxScroll uses 500
|
|
60
114
|
* ```
|
|
61
115
|
*/
|
|
62
|
-
export declare
|
|
116
|
+
export declare const clampedScrollTarget: (offsetBeforeScroll: number, keyboardHeight: number, contentHeight: number, layoutHeight: number, totalPaddingForMaxScroll?: number) => number;
|
|
63
117
|
/**
|
|
64
118
|
* Compute contentOffset.y for iOS lists.
|
|
65
119
|
*
|
|
66
120
|
* @param relativeScroll - Scroll position relative to current inset.
|
|
67
|
-
* @param keyboardHeight - Target keyboard height.
|
|
121
|
+
* @param keyboardHeight - Target keyboard height (used for scroll displacement).
|
|
68
122
|
* @param contentHeight - Total height of the scrollable content.
|
|
69
123
|
* @param layoutHeight - Visible height of the scroll view.
|
|
70
124
|
* @param inverted - Whether the list is inverted.
|
|
125
|
+
* @param totalPaddingForMaxScroll - Total padding to use for maxScroll calculation. When provided, used instead of keyboardHeight for the scrollable range. Defaults to keyboardHeight.
|
|
71
126
|
* @returns The absolute contentOffset.y to set.
|
|
72
127
|
* @example
|
|
73
128
|
* ```ts
|
|
74
129
|
* computeIOSContentOffset(100, 300, 1000, 800, false); // 400
|
|
75
130
|
* ```
|
|
76
131
|
*/
|
|
77
|
-
export declare
|
|
132
|
+
export declare const computeIOSContentOffset: (relativeScroll: number, keyboardHeight: number, contentHeight: number, layoutHeight: number, inverted: boolean, totalPaddingForMaxScroll?: number) => number;
|
|
@@ -11,10 +11,7 @@ import type Reanimated from "react-native-reanimated";
|
|
|
11
11
|
* @returns Shared values for padding and contentOffsetY (always `undefined`).
|
|
12
12
|
* @example
|
|
13
13
|
* ```tsx
|
|
14
|
-
* const { padding
|
|
15
|
-
* inverted: false,
|
|
16
|
-
* keyboardLiftBehavior: "always",
|
|
17
|
-
* });
|
|
14
|
+
* const { padding } = useChatKeyboard(ref, { inverted: false, keyboardLiftBehavior: "always" });
|
|
18
15
|
* ```
|
|
19
16
|
*/
|
|
20
17
|
declare function useChatKeyboard(scrollViewRef: AnimatedRef<Reanimated.ScrollView>, options: UseChatKeyboardOptions): UseChatKeyboardReturn;
|
|
@@ -6,6 +6,9 @@ type UseChatKeyboardOptions = {
|
|
|
6
6
|
keyboardLiftBehavior: KeyboardLiftBehavior;
|
|
7
7
|
freeze: boolean;
|
|
8
8
|
offset: number;
|
|
9
|
+
blankSpace: SharedValue<number>;
|
|
10
|
+
/** Extra content padding shared value — needed on iOS to correctly clamp contentOffset. */
|
|
11
|
+
extraContentPadding: SharedValue<number>;
|
|
9
12
|
};
|
|
10
13
|
type UseChatKeyboardReturn = {
|
|
11
14
|
/** Extra scrollable space (= keyboard height). Used as contentInset on iOS, contentInsetBottom/contentInsetTop on Android. */
|
|
@@ -14,6 +17,18 @@ type UseChatKeyboardReturn = {
|
|
|
14
17
|
currentHeight: SharedValue<number>;
|
|
15
18
|
/** Absolute Y content offset for iOS (set once in onStart). `undefined` on Android. */
|
|
16
19
|
contentOffsetY: SharedValue<number> | undefined;
|
|
20
|
+
/** Current vertical scroll offset. */
|
|
21
|
+
scroll: SharedValue<number>;
|
|
22
|
+
/** Visible viewport dimensions. */
|
|
23
|
+
layout: SharedValue<{
|
|
24
|
+
width: number;
|
|
25
|
+
height: number;
|
|
26
|
+
}>;
|
|
27
|
+
/** Total content dimensions. */
|
|
28
|
+
size: SharedValue<{
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
}>;
|
|
17
32
|
/** Callback to attach to ScrollView's onLayout prop to capture initial viewport dimensions. */
|
|
18
33
|
onLayout: (e: LayoutChangeEvent) => void;
|
|
19
34
|
/** Callback to attach to ScrollView's onContentSizeChange prop to capture initial content dimensions. */
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { KeyboardLiftBehavior } from "../useChatKeyboard/types";
|
|
2
|
+
import type { AnimatedRef, SharedValue } from "react-native-reanimated";
|
|
3
|
+
import type Reanimated from "react-native-reanimated";
|
|
4
|
+
type UseExtraContentPaddingOptions = {
|
|
5
|
+
scrollViewRef: AnimatedRef<Reanimated.ScrollView>;
|
|
6
|
+
extraContentPadding: SharedValue<number>;
|
|
7
|
+
/** Keyboard-only padding from useChatKeyboard — used to compute total padding for clamping. */
|
|
8
|
+
keyboardPadding: SharedValue<number>;
|
|
9
|
+
/** Minimum inset floor — used to absorb keyboard and extraContentPadding changes. */
|
|
10
|
+
blankSpace: SharedValue<number>;
|
|
11
|
+
/** Current vertical scroll offset. */
|
|
12
|
+
scroll: SharedValue<number>;
|
|
13
|
+
/** Visible viewport dimensions. */
|
|
14
|
+
layout: SharedValue<{
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
}>;
|
|
18
|
+
/** Total content dimensions. */
|
|
19
|
+
size: SharedValue<{
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}>;
|
|
23
|
+
inverted: boolean;
|
|
24
|
+
keyboardLiftBehavior: KeyboardLiftBehavior;
|
|
25
|
+
freeze: boolean;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Hook that reacts to `extraContentPadding` changes and conditionally
|
|
29
|
+
* adjusts the scroll position using `scrollTo` on both iOS and Android.
|
|
30
|
+
*
|
|
31
|
+
* Padding extension (scrollable range) is handled externally via a
|
|
32
|
+
* `useDerivedValue` that sums keyboard padding + extra content padding.
|
|
33
|
+
* This hook only handles the scroll correction.
|
|
34
|
+
*
|
|
35
|
+
* @param options - Configuration and shared values.
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* useExtraContentPadding({ scrollViewRef, extraContentPadding, ... });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
declare function useExtraContentPadding(options: UseExtraContentPaddingOptions): void;
|
|
42
|
+
export { useExtraContentPadding };
|
|
43
|
+
export type { UseExtraContentPaddingOptions };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { RCTKeyboardToolbarGroupView } from "../../bindings";
|
|
2
3
|
import { colors } from "./colors";
|
|
3
4
|
import { Background, Content, Done, Next, Prev } from "./compound/components";
|
|
4
5
|
import type { KeyboardToolbarProps } from "./types";
|
|
@@ -22,6 +23,7 @@ declare const KeyboardToolbar: React.FC<KeyboardToolbarProps> & {
|
|
|
22
23
|
Prev: typeof Prev;
|
|
23
24
|
Next: typeof Next;
|
|
24
25
|
Done: typeof Done;
|
|
26
|
+
Group: typeof RCTKeyboardToolbarGroupView;
|
|
25
27
|
};
|
|
26
28
|
export { colors as DefaultKeyboardToolbarTheme, KeyboardToolbarProps };
|
|
27
29
|
export default KeyboardToolbar;
|
|
@@ -9,7 +9,10 @@ declare const ScrollViewWithBottomPadding: React.ForwardRefExoticComponent<{
|
|
|
9
9
|
children?: React.ReactNode;
|
|
10
10
|
inverted?: boolean;
|
|
11
11
|
bottomPadding: SharedValue<number>;
|
|
12
|
+
/** Padding for scroll indicator insets (excludes blankSpace). Falls back to bottomPadding when not provided. */
|
|
13
|
+
scrollIndicatorPadding?: SharedValue<number>;
|
|
12
14
|
/** Absolute Y content offset (iOS only, for KeyboardChatScrollView). */
|
|
13
15
|
contentOffsetY?: SharedValue<number>;
|
|
16
|
+
applyWorkaroundForContentInsetHitTestBug?: boolean;
|
|
14
17
|
} & ScrollViewProps & React.RefAttributes<Reanimated.ScrollView>>;
|
|
15
18
|
export default ScrollViewWithBottomPadding;
|
|
@@ -4,6 +4,7 @@ import type { Double } from "react-native/Libraries/Types/CodegenTypes";
|
|
|
4
4
|
export interface NativeProps extends ViewProps {
|
|
5
5
|
contentInsetBottom: Double;
|
|
6
6
|
contentInsetTop: Double;
|
|
7
|
+
applyWorkaroundForContentInsetHitTestBug?: boolean;
|
|
7
8
|
}
|
|
8
9
|
declare const _default: HostComponent<NativeProps>;
|
|
9
10
|
export default _default;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { HostComponent } from "react-native";
|
|
2
|
+
import type { ViewProps } from "react-native/Libraries/Components/View/ViewPropTypes";
|
|
3
|
+
export interface NativeProps extends ViewProps {
|
|
4
|
+
}
|
|
5
|
+
declare const _default: HostComponent<NativeProps>;
|
|
6
|
+
export default _default;
|
|
@@ -6,6 +6,7 @@ export interface Spec extends TurboModule {
|
|
|
6
6
|
preload(): void;
|
|
7
7
|
dismiss(keepFocus: boolean, animated: boolean): void;
|
|
8
8
|
setFocusTo(direction: string): void;
|
|
9
|
+
viewPositionInWindow(viewTag: number): Promise<object>;
|
|
9
10
|
addListener: (eventName: string) => void;
|
|
10
11
|
removeListeners: (count: number) => void;
|
|
11
12
|
}
|
|
@@ -97,12 +97,19 @@ export type KeyboardControllerModule = {
|
|
|
97
97
|
*/
|
|
98
98
|
state: () => KeyboardEventData;
|
|
99
99
|
};
|
|
100
|
+
export type ViewPositionInWindowResult = {
|
|
101
|
+
x: number;
|
|
102
|
+
y: number;
|
|
103
|
+
width: number;
|
|
104
|
+
height: number;
|
|
105
|
+
};
|
|
100
106
|
export type KeyboardControllerNativeModule = {
|
|
101
107
|
setDefaultMode: () => void;
|
|
102
108
|
setInputMode: (mode: number) => void;
|
|
103
109
|
preload: () => void;
|
|
104
110
|
dismiss: (keepFocus: boolean, animated: boolean) => void;
|
|
105
111
|
setFocusTo: (direction: Direction) => void;
|
|
112
|
+
viewPositionInWindow: (viewTag: number) => Promise<ViewPositionInWindowResult>;
|
|
106
113
|
addListener: (eventName: string) => void;
|
|
107
114
|
removeListeners: (count: number) => void;
|
|
108
115
|
};
|
|
@@ -48,9 +48,11 @@ export type KeyboardExtenderProps = PropsWithChildren<{
|
|
|
48
48
|
/** Controls whether this `KeyboardExtender` instance should take an effect. Default is `true`. */
|
|
49
49
|
enabled?: boolean;
|
|
50
50
|
}>;
|
|
51
|
+
export type KeyboardToolbarGroupViewProps = PropsWithChildren<ViewProps>;
|
|
51
52
|
export type ClippingScrollViewProps = PropsWithChildren<ViewProps & {
|
|
52
53
|
/** An additional space that gets applied to the bottom of the `ScrollView` (inside a scrollable content). Default is `0`. */
|
|
53
54
|
contentInsetBottom?: number;
|
|
54
55
|
/** An additional space that gets applied to the top of the `ScrollView` (inside a scrollable content). Default is `0`. */
|
|
55
56
|
contentInsetTop?: number;
|
|
57
|
+
applyWorkaroundForContentInsetHitTestBug?: boolean;
|
|
56
58
|
}>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-keyboard-controller",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.1",
|
|
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",
|
|
@@ -67,6 +67,8 @@
|
|
|
67
67
|
"keyboard next button",
|
|
68
68
|
"keyboard previous button",
|
|
69
69
|
"extend keyboard",
|
|
70
|
+
"chat",
|
|
71
|
+
"chat scroll view",
|
|
70
72
|
"ios",
|
|
71
73
|
"android"
|
|
72
74
|
],
|
|
@@ -191,7 +193,9 @@
|
|
|
191
193
|
"KeyboardGestureArea": "KeyboardGestureArea",
|
|
192
194
|
"OverKeyboardView": "OverKeyboardView",
|
|
193
195
|
"KeyboardBackgroundView": "KeyboardBackgroundView",
|
|
194
|
-
"KeyboardExtender": "KeyboardExtender"
|
|
196
|
+
"KeyboardExtender": "KeyboardExtender",
|
|
197
|
+
"ClippingScrollViewDecoratorView": "ClippingScrollViewDecoratorView",
|
|
198
|
+
"KeyboardToolbarGroupView": "KeyboardToolbarGroupView"
|
|
195
199
|
}
|
|
196
200
|
}
|
|
197
201
|
},
|
package/react-native.config.js
CHANGED
|
@@ -7,6 +7,8 @@ module.exports = {
|
|
|
7
7
|
"KeyboardGestureAreaComponentDescriptor",
|
|
8
8
|
"OverKeyboardViewComponentDescriptor",
|
|
9
9
|
"KeyboardBackgroundViewComponentDescriptor",
|
|
10
|
+
"ClippingScrollViewDecoratorViewComponentDescriptor",
|
|
11
|
+
"KeyboardToolbarGroupViewComponentDescriptor",
|
|
10
12
|
],
|
|
11
13
|
cmakeListsPath: "../android/src/main/jni/CMakeLists.txt",
|
|
12
14
|
},
|
package/src/bindings.native.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { NativeEventEmitter, Platform } from "react-native";
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
-
ClippingScrollViewProps,
|
|
5
4
|
FocusedInputEventsModule,
|
|
6
5
|
KeyboardBackgroundViewProps,
|
|
7
6
|
KeyboardControllerNativeModule,
|
|
@@ -9,6 +8,7 @@ import type {
|
|
|
9
8
|
KeyboardEventsModule,
|
|
10
9
|
KeyboardExtenderProps,
|
|
11
10
|
KeyboardGestureAreaProps,
|
|
11
|
+
KeyboardToolbarGroupViewProps,
|
|
12
12
|
OverKeyboardViewProps,
|
|
13
13
|
WindowDimensionsEventsModule,
|
|
14
14
|
} from "./types";
|
|
@@ -73,6 +73,6 @@ export const RCTKeyboardExtender: React.FC<KeyboardExtenderProps> =
|
|
|
73
73
|
? require("./specs/KeyboardExtenderNativeComponent").default
|
|
74
74
|
: ({ children }: KeyboardExtenderProps) => children;
|
|
75
75
|
export const ClippingScrollView: React.FC<KeyboardBackgroundViewProps> =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
require("./specs/ClippingScrollViewDecoratorViewNativeComponent").default;
|
|
77
|
+
export const RCTKeyboardToolbarGroupView: React.FC<KeyboardToolbarGroupViewProps> =
|
|
78
|
+
require("./specs/KeyboardToolbarGroupViewNativeComponent").default;
|
package/src/bindings.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
KeyboardEventsModule,
|
|
10
10
|
KeyboardExtenderProps,
|
|
11
11
|
KeyboardGestureAreaProps,
|
|
12
|
+
KeyboardToolbarGroupViewProps,
|
|
12
13
|
OverKeyboardViewProps,
|
|
13
14
|
WindowDimensionsEventsModule,
|
|
14
15
|
} from "./types";
|
|
@@ -22,6 +23,8 @@ export const KeyboardControllerNative: KeyboardControllerNativeModule = {
|
|
|
22
23
|
preload: NOOP,
|
|
23
24
|
dismiss: NOOP,
|
|
24
25
|
setFocusTo: NOOP,
|
|
26
|
+
viewPositionInWindow: () =>
|
|
27
|
+
Promise.resolve({ x: 0, y: 0, width: 0, height: 0 }),
|
|
25
28
|
addListener: NOOP,
|
|
26
29
|
removeListeners: NOOP,
|
|
27
30
|
};
|
|
@@ -84,9 +87,20 @@ export const KeyboardBackgroundView =
|
|
|
84
87
|
export const RCTKeyboardExtender =
|
|
85
88
|
View as unknown as React.FC<KeyboardExtenderProps>;
|
|
86
89
|
/**
|
|
87
|
-
* A decorator that will clip the content of the `ScrollView`. It helps to simulate `contentInset` behavior on Android
|
|
90
|
+
* A decorator that will clip the content of the `ScrollView`. It helps to simulate `contentInset` behavior on Android
|
|
88
91
|
* Supports only `bottom` property (`paddingBottom` is not supported property of `ScrollView.style`).
|
|
89
92
|
* Using this component we can modify bottom inset without having a fake view.
|
|
93
|
+
*
|
|
94
|
+
* On iOS we use swizzling to apply runtime patches to fix some broken internal methods.
|
|
95
|
+
* Ideally this component shouldn't exist and all its fixes/polyfills must be added directly to react-native and
|
|
96
|
+
* we will port features/fixes back to upstream, but at the moment we use this view to
|
|
97
|
+
* deliver desired functionality regardless of react-native version used.
|
|
90
98
|
*/
|
|
91
99
|
export const ClippingScrollView =
|
|
92
100
|
View as unknown as React.FC<ClippingScrollViewProps>;
|
|
101
|
+
/**
|
|
102
|
+
* A View that defines a group of `TextInput`s.
|
|
103
|
+
* Used in toolbar navigation to assure that you can navigate only between inputs withing the same group.
|
|
104
|
+
*/
|
|
105
|
+
export const RCTKeyboardToolbarGroupView =
|
|
106
|
+
View as unknown as React.FC<KeyboardToolbarGroupViewProps>;
|
|
@@ -8,7 +8,10 @@ import Reanimated, {
|
|
|
8
8
|
useSharedValue,
|
|
9
9
|
} from "react-native-reanimated";
|
|
10
10
|
|
|
11
|
+
import { KeyboardControllerNative } from "../../bindings";
|
|
11
12
|
import { useWindowDimensions } from "../../hooks";
|
|
13
|
+
import { findNodeHandle } from "../../utils/findNodeHandle";
|
|
14
|
+
import useCombinedRef from "../hooks/useCombinedRef";
|
|
12
15
|
|
|
13
16
|
import { useKeyboardAnimation, useTranslateAnimation } from "./hooks";
|
|
14
17
|
|
|
@@ -26,33 +29,29 @@ export type KeyboardAvoidingViewBaseProps = {
|
|
|
26
29
|
* may be non-zero in some cases. Defaults to 0.
|
|
27
30
|
*/
|
|
28
31
|
keyboardVerticalOffset?: number;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* When `true`, the view automatically detects its position on screen,
|
|
35
|
+
* accounting for navigation headers, modals, and other layout offsets.
|
|
36
|
+
* This means `keyboardVerticalOffset` becomes purely additive extra
|
|
37
|
+
* space rather than compensation for unknown positioning.
|
|
38
|
+
*
|
|
39
|
+
* Defaults to `false` for backward compatibility.
|
|
40
|
+
*/
|
|
41
|
+
automaticOffset?: boolean;
|
|
29
42
|
} & ViewProps;
|
|
30
43
|
|
|
31
|
-
export type KeyboardAvoidingViewProps = KeyboardAvoidingViewBaseProps &
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
contentContainerStyle?: ViewProps["style"];
|
|
43
|
-
}
|
|
44
|
-
| {
|
|
45
|
-
/**
|
|
46
|
-
* Specify how to react to the presence of the keyboard.
|
|
47
|
-
*/
|
|
48
|
-
behavior?: "height" | "padding" | "translate-with-padding";
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* `contentContainerStyle` is not allowed for these behaviors.
|
|
52
|
-
*/
|
|
53
|
-
contentContainerStyle?: never;
|
|
54
|
-
}
|
|
55
|
-
);
|
|
44
|
+
export type KeyboardAvoidingViewProps = KeyboardAvoidingViewBaseProps & {
|
|
45
|
+
/**
|
|
46
|
+
* Specify how to react to the presence of the keyboard.
|
|
47
|
+
*/
|
|
48
|
+
behavior?: "height" | "padding" | "position" | "translate-with-padding";
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Style of the content container when `behavior` is 'position'.
|
|
52
|
+
*/
|
|
53
|
+
contentContainerStyle?: ViewProps["style"];
|
|
54
|
+
};
|
|
56
55
|
|
|
57
56
|
const defaultLayout: LayoutRectangle = {
|
|
58
57
|
x: 0,
|
|
@@ -85,6 +84,7 @@ const KeyboardAvoidingView = forwardRef<
|
|
|
85
84
|
contentContainerStyle,
|
|
86
85
|
enabled = true,
|
|
87
86
|
keyboardVerticalOffset = 0,
|
|
87
|
+
automaticOffset = false,
|
|
88
88
|
style,
|
|
89
89
|
onLayout: onLayoutProps,
|
|
90
90
|
...props
|
|
@@ -92,6 +92,7 @@ const KeyboardAvoidingView = forwardRef<
|
|
|
92
92
|
ref,
|
|
93
93
|
) => {
|
|
94
94
|
const initialFrame = useSharedValue<LayoutRectangle | null>(null);
|
|
95
|
+
const internalRef = React.useRef<View | null>(null);
|
|
95
96
|
const frame = useDerivedValue(() => initialFrame.value || defaultLayout);
|
|
96
97
|
|
|
97
98
|
const { translate, padding } = useTranslateAnimation();
|
|
@@ -132,10 +133,35 @@ const KeyboardAvoidingView = forwardRef<
|
|
|
132
133
|
);
|
|
133
134
|
const onLayout = useCallback<NonNullable<ViewProps["onLayout"]>>(
|
|
134
135
|
(e) => {
|
|
135
|
-
runOnUI(onLayoutWorklet)(e.nativeEvent.layout);
|
|
136
136
|
onLayoutProps?.(e);
|
|
137
|
+
|
|
138
|
+
const layout = e.nativeEvent.layout;
|
|
139
|
+
|
|
140
|
+
if (automaticOffset) {
|
|
141
|
+
const tag = findNodeHandle(internalRef.current);
|
|
142
|
+
|
|
143
|
+
if (tag !== null) {
|
|
144
|
+
// Use native `viewPositionInWindow` to get true screen-absolute coordinates.
|
|
145
|
+
// This fixes current RN bugs:
|
|
146
|
+
// - https://github.com/facebook/react-native/pull/56062
|
|
147
|
+
// - https://github.com/facebook/react-native/pull/56056
|
|
148
|
+
return KeyboardControllerNative.viewPositionInWindow(tag)
|
|
149
|
+
.then((position) => {
|
|
150
|
+
runOnUI(onLayoutWorklet)({
|
|
151
|
+
...layout,
|
|
152
|
+
x: position.x,
|
|
153
|
+
y: position.y,
|
|
154
|
+
});
|
|
155
|
+
})
|
|
156
|
+
.catch(() => {
|
|
157
|
+
runOnUI(onLayoutWorklet)(layout);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return runOnUI(onLayoutWorklet)(layout);
|
|
137
163
|
},
|
|
138
|
-
[onLayoutProps],
|
|
164
|
+
[onLayoutProps, automaticOffset],
|
|
139
165
|
);
|
|
140
166
|
|
|
141
167
|
const animatedStyle = useAnimatedStyle(() => {
|
|
@@ -177,6 +203,7 @@ const KeyboardAvoidingView = forwardRef<
|
|
|
177
203
|
return {};
|
|
178
204
|
}
|
|
179
205
|
}, [behavior, enabled, interpolateToRelativeKeyboardHeight]);
|
|
206
|
+
const combinedRef = useCombinedRef(internalRef, ref);
|
|
180
207
|
const isPositionBehavior = behavior === "position";
|
|
181
208
|
const containerStyle = isPositionBehavior ? contentContainerStyle : style;
|
|
182
209
|
const combinedStyles = useMemo(
|
|
@@ -186,7 +213,7 @@ const KeyboardAvoidingView = forwardRef<
|
|
|
186
213
|
|
|
187
214
|
if (isPositionBehavior) {
|
|
188
215
|
return (
|
|
189
|
-
<View ref={
|
|
216
|
+
<View ref={combinedRef} style={style} onLayout={onLayout} {...props}>
|
|
190
217
|
<Reanimated.View style={combinedStyles}>{children}</Reanimated.View>
|
|
191
218
|
</View>
|
|
192
219
|
);
|
|
@@ -194,7 +221,7 @@ const KeyboardAvoidingView = forwardRef<
|
|
|
194
221
|
|
|
195
222
|
return (
|
|
196
223
|
<Reanimated.View
|
|
197
|
-
ref={
|
|
224
|
+
ref={combinedRef}
|
|
198
225
|
style={combinedStyles}
|
|
199
226
|
onLayout={onLayout}
|
|
200
227
|
{...props}
|
|
@@ -16,6 +16,7 @@ import Reanimated, {
|
|
|
16
16
|
useSharedValue,
|
|
17
17
|
} from "react-native-reanimated";
|
|
18
18
|
|
|
19
|
+
import { KeyboardControllerNative } from "../../bindings";
|
|
19
20
|
import {
|
|
20
21
|
useFocusedInputHandler,
|
|
21
22
|
useReanimatedFocusedInput,
|
|
@@ -150,14 +151,29 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
150
151
|
useSharedValue<FocusedInputSelectionChangedEvent | null>(null);
|
|
151
152
|
const ghostViewSpace = useSharedValue(-1);
|
|
152
153
|
const pendingSelectionForFocus = useSharedValue(false);
|
|
154
|
+
const scrollViewPageY = useSharedValue(0);
|
|
153
155
|
|
|
154
156
|
const { height } = useWindowDimensions();
|
|
155
157
|
|
|
156
158
|
const onScrollViewLayout = useCallback(
|
|
157
|
-
(e: LayoutChangeEvent) => {
|
|
158
|
-
|
|
159
|
+
async (e: LayoutChangeEvent) => {
|
|
160
|
+
const handle = findNodeHandle(scrollViewAnimatedRef.current);
|
|
161
|
+
|
|
162
|
+
scrollViewTarget.value = handle;
|
|
159
163
|
|
|
160
164
|
onLayout?.(e);
|
|
165
|
+
|
|
166
|
+
if (handle !== null) {
|
|
167
|
+
try {
|
|
168
|
+
const { y } = await KeyboardControllerNative.viewPositionInWindow(
|
|
169
|
+
handle,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
scrollViewPageY.value = y;
|
|
173
|
+
} catch {
|
|
174
|
+
// ignore
|
|
175
|
+
}
|
|
176
|
+
}
|
|
161
177
|
},
|
|
162
178
|
[onLayout],
|
|
163
179
|
);
|
|
@@ -205,7 +221,7 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
205
221
|
return interpolatedScrollTo;
|
|
206
222
|
}
|
|
207
223
|
|
|
208
|
-
if (point <
|
|
224
|
+
if (point < scrollViewPageY.value) {
|
|
209
225
|
const positionOnScreen = visibleRect - bottomOffset;
|
|
210
226
|
const topOfScreen = scrollPosition.value + point;
|
|
211
227
|
|
|
@@ -400,6 +416,7 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
400
416
|
keyboardWillChangeSize ||
|
|
401
417
|
focusWasChanged
|
|
402
418
|
) {
|
|
419
|
+
syncKeyboardFrame(e);
|
|
403
420
|
// persist scroll value
|
|
404
421
|
scrollPosition.value = position.value;
|
|
405
422
|
// just persist height - later will be used in interpolation
|
|
@@ -448,8 +465,6 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
448
465
|
onMove: (e) => {
|
|
449
466
|
"worklet";
|
|
450
467
|
|
|
451
|
-
syncKeyboardFrame(e);
|
|
452
|
-
|
|
453
468
|
if (removeGhostPadding(e.height)) {
|
|
454
469
|
return;
|
|
455
470
|
}
|