react-native-keyboard-controller 1.21.0-beta.1 → 1.21.0-beta.3
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/android/src/fabric/java/com/reactnativekeyboardcontroller/ClippingScrollViewDecoratorViewManager.kt +7 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/ClippingScrollViewDecoratorView.kt +28 -1
- package/android/src/paper/java/com/reactnativekeyboardcontroller/ClippingScrollViewDecoratorViewManager.kt +8 -0
- package/jest/index.js +1 -0
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js +7 -4
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardChatScrollView/hooks.js +13 -0
- package/lib/commonjs/components/KeyboardChatScrollView/hooks.js.map +1 -0
- package/lib/commonjs/components/KeyboardChatScrollView/index.js +80 -0
- package/lib/commonjs/components/KeyboardChatScrollView/index.js.map +1 -0
- package/lib/commonjs/components/KeyboardChatScrollView/types.js +6 -0
- package/lib/commonjs/components/KeyboardChatScrollView/types.js.map +1 -0
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/helpers.js +135 -0
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/helpers.js.map +1 -0
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js +121 -0
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js.map +1 -0
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.js +205 -0
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.js.map +1 -0
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/types.js +6 -0
- package/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/types.js.map +1 -0
- package/lib/commonjs/components/KeyboardStickyView/index.js +9 -5
- package/lib/commonjs/components/KeyboardStickyView/index.js.map +1 -1
- package/lib/commonjs/components/ScrollViewWithBottomPadding/index.js +46 -13
- package/lib/commonjs/components/ScrollViewWithBottomPadding/index.js.map +1 -1
- package/lib/commonjs/components/hooks/useScrollState.js +20 -1
- package/lib/commonjs/components/hooks/useScrollState.js.map +1 -1
- package/lib/commonjs/components/index.js +7 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/ClippingScrollViewDecoratorViewNativeComponent.js.map +1 -1
- package/lib/commonjs/types/views.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/index.js +7 -4
- package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/module/components/KeyboardChatScrollView/hooks.js +2 -0
- package/lib/module/components/KeyboardChatScrollView/hooks.js.map +1 -0
- package/lib/module/components/KeyboardChatScrollView/index.js +73 -0
- package/lib/module/components/KeyboardChatScrollView/index.js.map +1 -0
- package/lib/module/components/KeyboardChatScrollView/types.js +2 -0
- package/lib/module/components/KeyboardChatScrollView/types.js.map +1 -0
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/helpers.js +125 -0
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/helpers.js.map +1 -0
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js +115 -0
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js.map +1 -0
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.js +199 -0
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.js.map +1 -0
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/types.js +2 -0
- package/lib/module/components/KeyboardChatScrollView/useChatKeyboard/types.js.map +1 -0
- package/lib/module/components/KeyboardStickyView/index.js +9 -5
- package/lib/module/components/KeyboardStickyView/index.js.map +1 -1
- package/lib/module/components/ScrollViewWithBottomPadding/index.js +47 -14
- package/lib/module/components/ScrollViewWithBottomPadding/index.js.map +1 -1
- package/lib/module/components/hooks/useScrollState.js +21 -2
- package/lib/module/components/hooks/useScrollState.js.map +1 -1
- package/lib/module/components/index.js +1 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/ClippingScrollViewDecoratorViewNativeComponent.js.map +1 -1
- package/lib/module/types/views.js.map +1 -1
- package/lib/typescript/components/KeyboardChatScrollView/hooks.d.ts +2 -0
- package/lib/typescript/components/KeyboardChatScrollView/index.d.ts +12 -0
- package/lib/typescript/components/KeyboardChatScrollView/types.d.ts +48 -0
- package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/helpers.d.ts +77 -0
- package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/index.d.ts +21 -0
- package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/index.ios.d.ts +21 -0
- package/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/types.d.ts +22 -0
- package/lib/typescript/components/ScrollViewWithBottomPadding/index.d.ts +3 -0
- package/lib/typescript/components/hooks/useScrollState.d.ts +3 -0
- package/lib/typescript/components/index.d.ts +2 -0
- package/lib/typescript/index.d.ts +2 -2
- package/lib/typescript/specs/ClippingScrollViewDecoratorViewNativeComponent.d.ts +1 -0
- package/lib/typescript/types/views.d.ts +2 -0
- package/package.json +12 -4
- package/src/components/KeyboardAwareScrollView/index.tsx +10 -3
- package/src/components/KeyboardChatScrollView/hooks.ts +2 -0
- package/src/components/KeyboardChatScrollView/index.tsx +106 -0
- package/src/components/KeyboardChatScrollView/types.ts +49 -0
- package/src/components/KeyboardChatScrollView/useChatKeyboard/helpers.ts +163 -0
- package/src/components/KeyboardChatScrollView/useChatKeyboard/index.ios.ts +180 -0
- package/src/components/KeyboardChatScrollView/useChatKeyboard/index.ts +300 -0
- package/src/components/KeyboardChatScrollView/useChatKeyboard/types.ts +30 -0
- package/src/components/KeyboardStickyView/index.tsx +8 -8
- package/src/components/ScrollViewWithBottomPadding/index.tsx +63 -17
- package/src/components/hooks/useScrollState.ts +24 -2
- package/src/components/index.ts +2 -0
- package/src/index.ts +2 -0
- package/src/specs/ClippingScrollViewDecoratorViewNativeComponent.ts +1 -0
- package/src/types/views.ts +2 -0
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["KeyboardAvoidingView","KeyboardStickyView","KeyboardAwareScrollView","KeyboardToolbar","DefaultKeyboardToolbarTheme","OverKeyboardView","KeyboardExtender"],"sources":["index.ts"],"sourcesContent":["export * from \"./bindings\";\nexport * from \"./animated\";\nexport * from \"./context\";\nexport * from \"./hooks\";\nexport * from \"./constants\";\nexport * from \"./module\";\nexport * from \"./types\";\nexport * from \"./compat\";\n\nexport {\n KeyboardAvoidingView,\n KeyboardStickyView,\n KeyboardAwareScrollView,\n // keyboard toolbar\n KeyboardToolbar,\n DefaultKeyboardToolbarTheme,\n} from \"./components\";\nexport type {\n KeyboardAvoidingViewProps,\n KeyboardStickyViewProps,\n KeyboardAwareScrollViewProps,\n KeyboardAwareScrollViewRef,\n KeyboardToolbarProps,\n} from \"./components\";\nexport { OverKeyboardView, KeyboardExtender } from \"./views\";\n"],"mappings":"AAAA,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,WAAW;AACzB,cAAc,SAAS;AACvB,cAAc,aAAa;AAC3B,cAAc,UAAU;AACxB,cAAc,SAAS;AACvB,cAAc,UAAU;AAExB,SACEA,oBAAoB,EACpBC,kBAAkB,EAClBC,uBAAuB;AACvB;AACAC,eAAe,EACfC,2BAA2B,QACtB,cAAc;
|
|
1
|
+
{"version":3,"names":["KeyboardChatScrollView","KeyboardAvoidingView","KeyboardStickyView","KeyboardAwareScrollView","KeyboardToolbar","DefaultKeyboardToolbarTheme","OverKeyboardView","KeyboardExtender"],"sources":["index.ts"],"sourcesContent":["export * from \"./bindings\";\nexport * from \"./animated\";\nexport * from \"./context\";\nexport * from \"./hooks\";\nexport * from \"./constants\";\nexport * from \"./module\";\nexport * from \"./types\";\nexport * from \"./compat\";\n\nexport {\n KeyboardChatScrollView,\n KeyboardAvoidingView,\n KeyboardStickyView,\n KeyboardAwareScrollView,\n // keyboard toolbar\n KeyboardToolbar,\n DefaultKeyboardToolbarTheme,\n} from \"./components\";\nexport type {\n KeyboardChatScrollViewProps,\n KeyboardAvoidingViewProps,\n KeyboardStickyViewProps,\n KeyboardAwareScrollViewProps,\n KeyboardAwareScrollViewRef,\n KeyboardToolbarProps,\n} from \"./components\";\nexport { OverKeyboardView, KeyboardExtender } from \"./views\";\n"],"mappings":"AAAA,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,WAAW;AACzB,cAAc,SAAS;AACvB,cAAc,aAAa;AAC3B,cAAc,UAAU;AACxB,cAAc,SAAS;AACvB,cAAc,UAAU;AAExB,SACEA,sBAAsB,EACtBC,oBAAoB,EACpBC,kBAAkB,EAClBC,uBAAuB;AACvB;AACAC,eAAe,EACfC,2BAA2B,QACtB,cAAc;AASrB,SAASC,gBAAgB,EAAEC,gBAAgB,QAAQ,SAAS","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["codegenNativeComponent","interfaceOnly","excludedPlatforms"],"sources":["ClippingScrollViewDecoratorViewNativeComponent.ts"],"sourcesContent":["import { codegenNativeComponent } from \"react-native\";\n\nimport type { HostComponent } from \"react-native\";\nimport type { ViewProps } from \"react-native\";\nimport type { Double } from \"react-native/Libraries/Types/CodegenTypes\";\n\nexport interface NativeProps extends ViewProps {\n contentInsetBottom: Double;\n}\n\nexport default codegenNativeComponent<NativeProps>(\n \"ClippingScrollViewDecoratorView\",\n {\n interfaceOnly: true,\n excludedPlatforms: [\"iOS\"],\n },\n) as HostComponent<NativeProps>;\n"],"mappings":"AAAA,SAASA,sBAAsB,QAAQ,cAAc;
|
|
1
|
+
{"version":3,"names":["codegenNativeComponent","interfaceOnly","excludedPlatforms"],"sources":["ClippingScrollViewDecoratorViewNativeComponent.ts"],"sourcesContent":["import { codegenNativeComponent } from \"react-native\";\n\nimport type { HostComponent } from \"react-native\";\nimport type { ViewProps } from \"react-native\";\nimport type { Double } from \"react-native/Libraries/Types/CodegenTypes\";\n\nexport interface NativeProps extends ViewProps {\n contentInsetBottom: Double;\n contentInsetTop: Double;\n}\n\nexport default codegenNativeComponent<NativeProps>(\n \"ClippingScrollViewDecoratorView\",\n {\n interfaceOnly: true,\n excludedPlatforms: [\"iOS\"],\n },\n) as HostComponent<NativeProps>;\n"],"mappings":"AAAA,SAASA,sBAAsB,QAAQ,cAAc;AAWrD,eAAeA,sBAAsB,CACnC,iCAAiC,EACjC;EACEC,aAAa,EAAE,IAAI;EACnBC,iBAAiB,EAAE,CAAC,KAAK;AAC3B,CACF,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["views.ts"],"sourcesContent":["import type { PropsWithChildren } from \"react\";\nimport type { ViewProps } from \"react-native\";\n\nexport type KeyboardGestureAreaProps = {\n /**\n * Determines how the keyboard position will be controlled:\n * - `ios` - keyboard will be following finger only when finger touches keyboard\n * - `linear` - keyboard will be following finger position linearly.\n *\n * @platform android\n */\n interpolator?: \"ios\" | \"linear\";\n /**\n * Whether to allow to show a keyboard from dismissed state by swipe up.\n * Default to `false`.\n *\n * @platform android\n */\n showOnSwipeUp?: boolean;\n /**\n * Whether to allow to control a keyboard by gestures. The strategy how\n * it should be controlled is determined by `interpolator` property.\n * Defaults to `true`.\n *\n * @platform android\n */\n enableSwipeToDismiss?: boolean;\n /**\n * Extra distance to the keyboard.\n */\n offset?: number;\n /**\n * A corresponding `nativeID` value from the associated `TextInput` (a string that links the `KeyboardGestureArea` to one or more `TextInput` components).\n * This is **required on iOS** in order to apply the `offset` when the keyboard is shown. Only the currently focused `TextInput` with a matching `nativeID`\n * will receive offset behavior.\n *\n * @platform ios\n */\n textInputNativeID?: string;\n} & ViewProps;\nexport type OverKeyboardViewProps = PropsWithChildren<{\n /**\n * A boolean prop indicating whether the view is visible or not. If it's true then view is shown on the screen. If it's false then view is hidden.\n */\n visible: boolean;\n}>;\nexport type KeyboardBackgroundViewProps = PropsWithChildren<ViewProps>;\nexport type KeyboardExtenderProps = PropsWithChildren<{\n /** Controls whether this `KeyboardExtender` instance should take an effect. Default is `true`. */\n enabled?: boolean;\n}>;\nexport type ClippingScrollViewProps = PropsWithChildren<\n ViewProps & {\n /** An additional space that gets applied to the bottom of the `ScrollView` (inside a scrollable content). Default is `0`. */\n contentInsetBottom?: number;\n }\n>;\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["views.ts"],"sourcesContent":["import type { PropsWithChildren } from \"react\";\nimport type { ViewProps } from \"react-native\";\n\nexport type KeyboardGestureAreaProps = {\n /**\n * Determines how the keyboard position will be controlled:\n * - `ios` - keyboard will be following finger only when finger touches keyboard\n * - `linear` - keyboard will be following finger position linearly.\n *\n * @platform android\n */\n interpolator?: \"ios\" | \"linear\";\n /**\n * Whether to allow to show a keyboard from dismissed state by swipe up.\n * Default to `false`.\n *\n * @platform android\n */\n showOnSwipeUp?: boolean;\n /**\n * Whether to allow to control a keyboard by gestures. The strategy how\n * it should be controlled is determined by `interpolator` property.\n * Defaults to `true`.\n *\n * @platform android\n */\n enableSwipeToDismiss?: boolean;\n /**\n * Extra distance to the keyboard.\n */\n offset?: number;\n /**\n * A corresponding `nativeID` value from the associated `TextInput` (a string that links the `KeyboardGestureArea` to one or more `TextInput` components).\n * This is **required on iOS** in order to apply the `offset` when the keyboard is shown. Only the currently focused `TextInput` with a matching `nativeID`\n * will receive offset behavior.\n *\n * @platform ios\n */\n textInputNativeID?: string;\n} & ViewProps;\nexport type OverKeyboardViewProps = PropsWithChildren<{\n /**\n * A boolean prop indicating whether the view is visible or not. If it's true then view is shown on the screen. If it's false then view is hidden.\n */\n visible: boolean;\n}>;\nexport type KeyboardBackgroundViewProps = PropsWithChildren<ViewProps>;\nexport type KeyboardExtenderProps = PropsWithChildren<{\n /** Controls whether this `KeyboardExtender` instance should take an effect. Default is `true`. */\n enabled?: boolean;\n}>;\nexport type ClippingScrollViewProps = PropsWithChildren<\n ViewProps & {\n /** An additional space that gets applied to the bottom of the `ScrollView` (inside a scrollable content). Default is `0`. */\n contentInsetBottom?: number;\n /** An additional space that gets applied to the top of the `ScrollView` (inside a scrollable content). Default is `0`. */\n contentInsetTop?: number;\n }\n>;\n"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Reanimated from "react-native-reanimated";
|
|
3
|
+
declare const KeyboardChatScrollView: React.ForwardRefExoticComponent<{
|
|
4
|
+
ScrollViewComponent?: import("../ScrollViewWithBottomPadding").AnimatedScrollViewComponent;
|
|
5
|
+
inverted?: boolean;
|
|
6
|
+
offset?: number;
|
|
7
|
+
keyboardLiftBehavior?: import("./hooks").KeyboardLiftBehavior;
|
|
8
|
+
freeze?: boolean;
|
|
9
|
+
} & import("react-native").ScrollViewProps & {
|
|
10
|
+
children?: React.ReactNode | undefined;
|
|
11
|
+
} & React.RefAttributes<Reanimated.ScrollView>>;
|
|
12
|
+
export default KeyboardChatScrollView;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AnimatedScrollViewComponent } from "../ScrollViewWithBottomPadding";
|
|
2
|
+
import type { KeyboardLiftBehavior } from "./useChatKeyboard/types";
|
|
3
|
+
import type { ScrollViewProps } from "react-native";
|
|
4
|
+
export type KeyboardChatScrollViewProps = {
|
|
5
|
+
/** Custom component for `ScrollView`. Default is `ScrollView`. */
|
|
6
|
+
ScrollViewComponent?: AnimatedScrollViewComponent;
|
|
7
|
+
/** Whether list are using `inverted` prop. Default is `false`. */
|
|
8
|
+
inverted?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* The distance between the bottom of the screen and the `ScrollView`.
|
|
11
|
+
* When the keyboard appears, the `ScrollView` will only push content by the effective
|
|
12
|
+
* distance (`keyboardHeight - offset`) instead of the full keyboard height.
|
|
13
|
+
*
|
|
14
|
+
* Useful when the input is not at the very bottom of the screen (e.g., above safe area, above
|
|
15
|
+
* bottom tabs, etc. - in this case offset should be equal to the height of the elements between
|
|
16
|
+
* `ScrollView` and bottom of the screen).
|
|
17
|
+
*
|
|
18
|
+
* Default is `0`.
|
|
19
|
+
*/
|
|
20
|
+
offset?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Determines how the chat content should behave when the keyboard appears, specifically whether
|
|
23
|
+
* the scroll view should automatically lift its content to keep it visible above the keyboard.
|
|
24
|
+
*
|
|
25
|
+
* Possible values:
|
|
26
|
+
* - `'always'`: The content always lifts along with the keyboard, ensuring the messages from the bottom part of screen
|
|
27
|
+
* remain visible regardless of the current scroll position. This is the default behavior for most chat applications (used in Telegram).
|
|
28
|
+
* - `'whenAtEnd'`: The content lifts only if the scroll view is at the end (i.e., the last message
|
|
29
|
+
* is visible or near the bottom). This prevents unnecessary adjustments when the user is scrolling
|
|
30
|
+
* through older messages (ChatGPT mobile app behavior).
|
|
31
|
+
* - `'persistent'`: The content always lifts when the keyboard appears (similar to `'always'`), but
|
|
32
|
+
* does not reset (lower) when the keyboard hides. This mimics behaviors where the view remains adjusted
|
|
33
|
+
* after keyboard dismissal to maintain focus on the latest content without shifting back (Claude mobile app behavior).
|
|
34
|
+
* - `'never'`: The content does not lift at all when the keyboard appears. Use this for scenarios
|
|
35
|
+
* when you don't want to disturb user attention with animations (Perplexity mobile app behavior).
|
|
36
|
+
*
|
|
37
|
+
* Default is `'always'`.
|
|
38
|
+
*/
|
|
39
|
+
keyboardLiftBehavior?: KeyboardLiftBehavior;
|
|
40
|
+
/**
|
|
41
|
+
* When `true`, freezes all keyboard-driven layout changes (padding, content offset, scroll position).
|
|
42
|
+
* Useful when dismissing the keyboard to open a bottom sheet — prevents visual disruption
|
|
43
|
+
* while the sheet is visible.
|
|
44
|
+
*
|
|
45
|
+
* Default is `false`.
|
|
46
|
+
*/
|
|
47
|
+
freeze?: boolean;
|
|
48
|
+
} & ScrollViewProps;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { KeyboardLiftBehavior } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Map the current keyboard height to an effective height that accounts for a
|
|
4
|
+
* fixed offset (e.g. bottom safe-area or tab-bar height).
|
|
5
|
+
*
|
|
6
|
+
* @param height - Current keyboard height.
|
|
7
|
+
* @param targetKeyboardHeight - Full target keyboard height (captured on keyboard open).
|
|
8
|
+
* @param offset - Fixed distance between the scroll-view bottom and the screen bottom.
|
|
9
|
+
* @returns Effective height after subtracting the offset proportionally.
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* getEffectiveHeight(300, 300, 50); // 250
|
|
13
|
+
* getEffectiveHeight(150, 300, 50); // 125
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function getEffectiveHeight(height: number, targetKeyboardHeight: number, offset: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Check whether the scroll view is at the end of its content.
|
|
19
|
+
*
|
|
20
|
+
* For non-inverted lists the "end" is the bottom of the content.
|
|
21
|
+
* For inverted lists the "end" is the top (scroll offset near 0),
|
|
22
|
+
* because that is where the latest messages are displayed.
|
|
23
|
+
*
|
|
24
|
+
* @param scrollOffset - Current vertical scroll offset.
|
|
25
|
+
* @param layoutHeight - Visible height of the scroll view.
|
|
26
|
+
* @param contentHeight - Total height of the scrollable content.
|
|
27
|
+
* @param inverted - Whether the list is inverted.
|
|
28
|
+
* @returns `true` if the scroll position is within the threshold of the content end.
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const atEnd = isScrollAtEnd(100, 800, 920); // true (100 + 800 >= 920 - 20)
|
|
32
|
+
* const atEndInverted = isScrollAtEnd(5, 800, 2000, true); // true (5 <= 20)
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function isScrollAtEnd(scrollOffset: number, layoutHeight: number, contentHeight: number, inverted?: boolean): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Decide whether content should be shifted based on the keyboard lift behavior.
|
|
38
|
+
*
|
|
39
|
+
* @param behavior - The configured keyboard lift behavior.
|
|
40
|
+
* @param isAtEnd - Whether the scroll view is currently at the end.
|
|
41
|
+
* @returns `true` if content should be shifted.
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* shouldShiftContent("always", false); // true
|
|
45
|
+
* shouldShiftContent("whenAtEnd", false); // false
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function shouldShiftContent(behavior: KeyboardLiftBehavior, isAtEnd: boolean): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Compute the clamped scroll target for non-inverted lists.
|
|
51
|
+
*
|
|
52
|
+
* @param offsetBeforeScroll - Scroll position before keyboard appeared.
|
|
53
|
+
* @param keyboardHeight - Current keyboard height.
|
|
54
|
+
* @param contentHeight - Total height of the scrollable content.
|
|
55
|
+
* @param layoutHeight - Visible height of the scroll view.
|
|
56
|
+
* @returns Clamped scroll target between 0 and maxScroll.
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* clampedScrollTarget(100, 300, 1000, 800); // 400
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function clampedScrollTarget(offsetBeforeScroll: number, keyboardHeight: number, contentHeight: number, layoutHeight: number): number;
|
|
63
|
+
/**
|
|
64
|
+
* Compute contentOffset.y for iOS lists.
|
|
65
|
+
*
|
|
66
|
+
* @param relativeScroll - Scroll position relative to current inset.
|
|
67
|
+
* @param keyboardHeight - Target keyboard height.
|
|
68
|
+
* @param contentHeight - Total height of the scrollable content.
|
|
69
|
+
* @param layoutHeight - Visible height of the scroll view.
|
|
70
|
+
* @param inverted - Whether the list is inverted.
|
|
71
|
+
* @returns The absolute contentOffset.y to set.
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* computeIOSContentOffset(100, 300, 1000, 800, false); // 400
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function computeIOSContentOffset(relativeScroll: number, keyboardHeight: number, contentHeight: number, layoutHeight: number, inverted: boolean): number;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { UseChatKeyboardOptions, UseChatKeyboardReturn } from "./types";
|
|
2
|
+
import type { AnimatedRef } from "react-native-reanimated";
|
|
3
|
+
import type Reanimated from "react-native-reanimated";
|
|
4
|
+
/**
|
|
5
|
+
* Hook that manages keyboard-driven scrolling for chat-style scroll views.
|
|
6
|
+
* Calculates padding (extra scrollable space) and content shift values,
|
|
7
|
+
* using per-frame scrollTo updates (Android and other platforms).
|
|
8
|
+
*
|
|
9
|
+
* @param scrollViewRef - Animated ref to the scroll view.
|
|
10
|
+
* @param options - Configuration for inverted and keyboardLiftBehavior.
|
|
11
|
+
* @returns Shared values for padding and contentOffsetY (always `undefined`).
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const { padding, contentOffsetY } = useChatKeyboard(ref, {
|
|
15
|
+
* inverted: false,
|
|
16
|
+
* keyboardLiftBehavior: "always",
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare function useChatKeyboard(scrollViewRef: AnimatedRef<Reanimated.ScrollView>, options: UseChatKeyboardOptions): UseChatKeyboardReturn;
|
|
21
|
+
export { useChatKeyboard };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { UseChatKeyboardOptions, UseChatKeyboardReturn } from "./types";
|
|
2
|
+
import type { AnimatedRef } from "react-native-reanimated";
|
|
3
|
+
import type Reanimated from "react-native-reanimated";
|
|
4
|
+
/**
|
|
5
|
+
* Hook that manages keyboard-driven scrolling for chat-style scroll views.
|
|
6
|
+
* Calculates padding (extra scrollable space) and content shift values,
|
|
7
|
+
* using iOS-specific strategy (contentOffset set once in onStart).
|
|
8
|
+
*
|
|
9
|
+
* @param scrollViewRef - Animated ref to the scroll view.
|
|
10
|
+
* @param options - Configuration for inverted and keyboardLiftBehavior.
|
|
11
|
+
* @returns Shared values for padding and contentOffsetY.
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const { padding, contentOffsetY } = useChatKeyboard(ref, {
|
|
15
|
+
* inverted: false,
|
|
16
|
+
* keyboardLiftBehavior: "always",
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare function useChatKeyboard(scrollViewRef: AnimatedRef<Reanimated.ScrollView>, options: UseChatKeyboardOptions): UseChatKeyboardReturn;
|
|
21
|
+
export { useChatKeyboard };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LayoutChangeEvent } from "react-native";
|
|
2
|
+
import type { SharedValue } from "react-native-reanimated";
|
|
3
|
+
type KeyboardLiftBehavior = "always" | "whenAtEnd" | "persistent" | "never";
|
|
4
|
+
type UseChatKeyboardOptions = {
|
|
5
|
+
inverted: boolean;
|
|
6
|
+
keyboardLiftBehavior: KeyboardLiftBehavior;
|
|
7
|
+
freeze: boolean;
|
|
8
|
+
offset: number;
|
|
9
|
+
};
|
|
10
|
+
type UseChatKeyboardReturn = {
|
|
11
|
+
/** Extra scrollable space (= keyboard height). Used as contentInset on iOS, contentInsetBottom/contentInsetTop on Android. */
|
|
12
|
+
padding: SharedValue<number>;
|
|
13
|
+
/** Raw keyboard height updated every frame in onMove. Used to force Reanimated commits on Fabric. */
|
|
14
|
+
currentHeight: SharedValue<number>;
|
|
15
|
+
/** Absolute Y content offset for iOS (set once in onStart). `undefined` on Android. */
|
|
16
|
+
contentOffsetY: SharedValue<number> | undefined;
|
|
17
|
+
/** Callback to attach to ScrollView's onLayout prop to capture initial viewport dimensions. */
|
|
18
|
+
onLayout: (e: LayoutChangeEvent) => void;
|
|
19
|
+
/** Callback to attach to ScrollView's onContentSizeChange prop to capture initial content dimensions. */
|
|
20
|
+
onContentSizeChange: (w: number, h: number) => void;
|
|
21
|
+
};
|
|
22
|
+
export type { KeyboardLiftBehavior, UseChatKeyboardOptions, UseChatKeyboardReturn, };
|
|
@@ -7,6 +7,9 @@ export type AnimatedScrollViewComponent = React.ForwardRefExoticComponent<Animat
|
|
|
7
7
|
declare const ScrollViewWithBottomPadding: React.ForwardRefExoticComponent<{
|
|
8
8
|
ScrollViewComponent: AnimatedScrollViewComponent;
|
|
9
9
|
children?: React.ReactNode;
|
|
10
|
+
inverted?: boolean;
|
|
10
11
|
bottomPadding: SharedValue<number>;
|
|
12
|
+
/** Absolute Y content offset (iOS only, for KeyboardChatScrollView). */
|
|
13
|
+
contentOffsetY?: SharedValue<number>;
|
|
11
14
|
} & ScrollViewProps & React.RefAttributes<Reanimated.ScrollView>>;
|
|
12
15
|
export default ScrollViewWithBottomPadding;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { LayoutChangeEvent } from "react-native";
|
|
1
2
|
import type { AnimatedRef } from "react-native-reanimated";
|
|
2
3
|
import type Reanimated from "react-native-reanimated";
|
|
3
4
|
declare const useScrollState: (ref: AnimatedRef<Reanimated.ScrollView>) => {
|
|
@@ -10,5 +11,7 @@ declare const useScrollState: (ref: AnimatedRef<Reanimated.ScrollView>) => {
|
|
|
10
11
|
width: number;
|
|
11
12
|
height: number;
|
|
12
13
|
}>;
|
|
14
|
+
onLayout: (e: LayoutChangeEvent) => void;
|
|
15
|
+
onContentSizeChange: (w: number, h: number) => void;
|
|
13
16
|
};
|
|
14
17
|
export default useScrollState;
|
|
@@ -2,7 +2,9 @@ export { default as KeyboardAvoidingView } from "./KeyboardAvoidingView";
|
|
|
2
2
|
export { default as KeyboardStickyView } from "./KeyboardStickyView";
|
|
3
3
|
export { default as KeyboardAwareScrollView } from "./KeyboardAwareScrollView";
|
|
4
4
|
export { default as KeyboardToolbar, DefaultKeyboardToolbarTheme, } from "./KeyboardToolbar";
|
|
5
|
+
export { default as KeyboardChatScrollView } from "./KeyboardChatScrollView";
|
|
5
6
|
export type { KeyboardAvoidingViewProps } from "./KeyboardAvoidingView";
|
|
6
7
|
export type { KeyboardStickyViewProps } from "./KeyboardStickyView";
|
|
7
8
|
export type { KeyboardAwareScrollViewProps, KeyboardAwareScrollViewRef, } from "./KeyboardAwareScrollView";
|
|
8
9
|
export type { KeyboardToolbarProps } from "./KeyboardToolbar";
|
|
10
|
+
export type { KeyboardChatScrollViewProps } from "./KeyboardChatScrollView/types";
|
|
@@ -6,6 +6,6 @@ export * from "./constants";
|
|
|
6
6
|
export * from "./module";
|
|
7
7
|
export * from "./types";
|
|
8
8
|
export * from "./compat";
|
|
9
|
-
export { KeyboardAvoidingView, KeyboardStickyView, KeyboardAwareScrollView, KeyboardToolbar, DefaultKeyboardToolbarTheme, } from "./components";
|
|
10
|
-
export type { KeyboardAvoidingViewProps, KeyboardStickyViewProps, KeyboardAwareScrollViewProps, KeyboardAwareScrollViewRef, KeyboardToolbarProps, } from "./components";
|
|
9
|
+
export { KeyboardChatScrollView, KeyboardAvoidingView, KeyboardStickyView, KeyboardAwareScrollView, KeyboardToolbar, DefaultKeyboardToolbarTheme, } from "./components";
|
|
10
|
+
export type { KeyboardChatScrollViewProps, KeyboardAvoidingViewProps, KeyboardStickyViewProps, KeyboardAwareScrollViewProps, KeyboardAwareScrollViewRef, KeyboardToolbarProps, } from "./components";
|
|
11
11
|
export { OverKeyboardView, KeyboardExtender } from "./views";
|
|
@@ -3,6 +3,7 @@ import type { ViewProps } from "react-native";
|
|
|
3
3
|
import type { Double } from "react-native/Libraries/Types/CodegenTypes";
|
|
4
4
|
export interface NativeProps extends ViewProps {
|
|
5
5
|
contentInsetBottom: Double;
|
|
6
|
+
contentInsetTop: Double;
|
|
6
7
|
}
|
|
7
8
|
declare const _default: HostComponent<NativeProps>;
|
|
8
9
|
export default _default;
|
|
@@ -51,4 +51,6 @@ export type KeyboardExtenderProps = PropsWithChildren<{
|
|
|
51
51
|
export type ClippingScrollViewProps = PropsWithChildren<ViewProps & {
|
|
52
52
|
/** An additional space that gets applied to the bottom of the `ScrollView` (inside a scrollable content). Default is `0`. */
|
|
53
53
|
contentInsetBottom?: number;
|
|
54
|
+
/** An additional space that gets applied to the top of the `ScrollView` (inside a scrollable content). Default is `0`. */
|
|
55
|
+
contentInsetTop?: number;
|
|
54
56
|
}>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-keyboard-controller",
|
|
3
|
-
"version": "1.21.0-beta.
|
|
3
|
+
"version": "1.21.0-beta.3",
|
|
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",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"typescript": "tsc --noEmit --project tsconfig.build.json",
|
|
42
42
|
"lint": "eslint --quiet \"**/*.{js,ts,tsx}\"",
|
|
43
43
|
"lint-clang": "find ios/ -iname *.h -o -iname *.m -o -iname *.mm | grep -v -e Pods -e build | xargs clang-format -i -n --Werror",
|
|
44
|
-
"prepare": "bob build",
|
|
44
|
+
"prepare": "bob build > /dev/null 2>&1",
|
|
45
45
|
"release": "release-it",
|
|
46
46
|
"example": "yarn --cwd example",
|
|
47
47
|
"pods": "cd example && pod-install --quiet",
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"@react-native/eslint-config": "0.81.4",
|
|
90
90
|
"@release-it/conventional-changelog": "^2.0.0",
|
|
91
91
|
"@testing-library/react-hooks": "^8.0.1",
|
|
92
|
+
"@testing-library/react-native": "^13.3.3",
|
|
92
93
|
"@types/jest": "^29.5.13",
|
|
93
94
|
"@types/react": "^19.0.0",
|
|
94
95
|
"@types/react-test-renderer": "^19.0.0",
|
|
@@ -115,7 +116,7 @@
|
|
|
115
116
|
"react-native": "0.81.4",
|
|
116
117
|
"react-native-builder-bob": "^0.18.0",
|
|
117
118
|
"react-native-reanimated": "3.19.2",
|
|
118
|
-
"react-test-renderer": "19.
|
|
119
|
+
"react-test-renderer": "19.1.0",
|
|
119
120
|
"release-it": "^14.2.2",
|
|
120
121
|
"typescript": "5.8.3"
|
|
121
122
|
},
|
|
@@ -129,6 +130,12 @@
|
|
|
129
130
|
"modulePathIgnorePatterns": [
|
|
130
131
|
"<rootDir>/example/node_modules",
|
|
131
132
|
"<rootDir>/lib/"
|
|
133
|
+
],
|
|
134
|
+
"transformIgnorePatterns": [
|
|
135
|
+
"node_modules/(?!((jest-)?react-native|@react-native(-community)?|react-native-reanimated)/)"
|
|
136
|
+
],
|
|
137
|
+
"setupFiles": [
|
|
138
|
+
"./jestSetup.js"
|
|
132
139
|
]
|
|
133
140
|
},
|
|
134
141
|
"commitlint": {
|
|
@@ -187,5 +194,6 @@
|
|
|
187
194
|
"KeyboardExtender": "KeyboardExtender"
|
|
188
195
|
}
|
|
189
196
|
}
|
|
190
|
-
}
|
|
197
|
+
},
|
|
198
|
+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
191
199
|
}
|
|
@@ -497,11 +497,18 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
497
497
|
() => {
|
|
498
498
|
const scrollView = scrollViewRef.current;
|
|
499
499
|
|
|
500
|
-
|
|
500
|
+
if (scrollView) {
|
|
501
|
+
const scrollViewWithMethods =
|
|
502
|
+
scrollView as KeyboardAwareScrollViewRef;
|
|
501
503
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
+
scrollViewWithMethods.assureFocusedInputVisible = () => {
|
|
505
|
+
synchronize();
|
|
506
|
+
};
|
|
504
507
|
|
|
508
|
+
return scrollViewWithMethods;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return {
|
|
505
512
|
assureFocusedInputVisible: () => {
|
|
506
513
|
synchronize();
|
|
507
514
|
},
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React, { forwardRef, useCallback, useMemo } from "react";
|
|
2
|
+
import { StyleSheet } from "react-native";
|
|
3
|
+
import { useAnimatedRef, useAnimatedStyle } from "react-native-reanimated";
|
|
4
|
+
import Reanimated from "react-native-reanimated";
|
|
5
|
+
|
|
6
|
+
import useCombinedRef from "../hooks/useCombinedRef";
|
|
7
|
+
import ScrollViewWithBottomPadding from "../ScrollViewWithBottomPadding";
|
|
8
|
+
|
|
9
|
+
import { useChatKeyboard } from "./useChatKeyboard";
|
|
10
|
+
|
|
11
|
+
import type { KeyboardChatScrollViewProps } from "./types";
|
|
12
|
+
import type { LayoutChangeEvent } from "react-native";
|
|
13
|
+
|
|
14
|
+
const KeyboardChatScrollView = forwardRef<
|
|
15
|
+
Reanimated.ScrollView,
|
|
16
|
+
React.PropsWithChildren<KeyboardChatScrollViewProps>
|
|
17
|
+
>(
|
|
18
|
+
(
|
|
19
|
+
{
|
|
20
|
+
children,
|
|
21
|
+
ScrollViewComponent = Reanimated.ScrollView,
|
|
22
|
+
inverted = false,
|
|
23
|
+
keyboardLiftBehavior = "always",
|
|
24
|
+
freeze = false,
|
|
25
|
+
offset = 0,
|
|
26
|
+
onLayout: onLayoutProp,
|
|
27
|
+
onContentSizeChange: onContentSizeChangeProp,
|
|
28
|
+
...rest
|
|
29
|
+
},
|
|
30
|
+
ref,
|
|
31
|
+
) => {
|
|
32
|
+
const scrollViewRef = useAnimatedRef<Reanimated.ScrollView>();
|
|
33
|
+
const onRef = useCombinedRef(ref, scrollViewRef);
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
padding,
|
|
37
|
+
currentHeight,
|
|
38
|
+
contentOffsetY,
|
|
39
|
+
onLayout: onLayoutInternal,
|
|
40
|
+
onContentSizeChange: onContentSizeChangeInternal,
|
|
41
|
+
} = useChatKeyboard(scrollViewRef, {
|
|
42
|
+
inverted,
|
|
43
|
+
keyboardLiftBehavior,
|
|
44
|
+
freeze,
|
|
45
|
+
offset,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const onLayout = useCallback(
|
|
49
|
+
(e: LayoutChangeEvent) => {
|
|
50
|
+
onLayoutInternal(e);
|
|
51
|
+
onLayoutProp?.(e);
|
|
52
|
+
},
|
|
53
|
+
[onLayoutInternal, onLayoutProp],
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const onContentSizeChange = useCallback(
|
|
57
|
+
(w: number, h: number) => {
|
|
58
|
+
onContentSizeChangeInternal(w, h);
|
|
59
|
+
onContentSizeChangeProp?.(w, h);
|
|
60
|
+
},
|
|
61
|
+
[onContentSizeChangeInternal, onContentSizeChangeProp],
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Invisible view whose animated style changes every frame during keyboard
|
|
65
|
+
// animation. On Fabric, this forces Reanimated to schedule a commit,
|
|
66
|
+
// which flushes the scrollTo call in the same frame (fixing de-synchronization).
|
|
67
|
+
// see https://github.com/software-mansion/react-native-reanimated/issues/9000
|
|
68
|
+
const commitStyle = useAnimatedStyle(
|
|
69
|
+
() => ({
|
|
70
|
+
transform: [{ translateY: -currentHeight.value }],
|
|
71
|
+
}),
|
|
72
|
+
[],
|
|
73
|
+
);
|
|
74
|
+
const commit = useMemo(
|
|
75
|
+
() => [styles.commitView, commitStyle],
|
|
76
|
+
[commitStyle],
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<>
|
|
81
|
+
<ScrollViewWithBottomPadding
|
|
82
|
+
ref={onRef}
|
|
83
|
+
{...rest}
|
|
84
|
+
bottomPadding={padding}
|
|
85
|
+
contentOffsetY={contentOffsetY}
|
|
86
|
+
inverted={inverted}
|
|
87
|
+
ScrollViewComponent={ScrollViewComponent}
|
|
88
|
+
onContentSizeChange={onContentSizeChange}
|
|
89
|
+
onLayout={onLayout}
|
|
90
|
+
>
|
|
91
|
+
{children}
|
|
92
|
+
</ScrollViewWithBottomPadding>
|
|
93
|
+
<Reanimated.View style={commit} />
|
|
94
|
+
</>
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const styles = StyleSheet.create({
|
|
100
|
+
commitView: {
|
|
101
|
+
display: "none",
|
|
102
|
+
position: "absolute",
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
export default KeyboardChatScrollView;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AnimatedScrollViewComponent } from "../ScrollViewWithBottomPadding";
|
|
2
|
+
import type { KeyboardLiftBehavior } from "./useChatKeyboard/types";
|
|
3
|
+
import type { ScrollViewProps } from "react-native";
|
|
4
|
+
|
|
5
|
+
export type KeyboardChatScrollViewProps = {
|
|
6
|
+
/** Custom component for `ScrollView`. Default is `ScrollView`. */
|
|
7
|
+
ScrollViewComponent?: AnimatedScrollViewComponent;
|
|
8
|
+
/** Whether list are using `inverted` prop. Default is `false`. */
|
|
9
|
+
inverted?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* The distance between the bottom of the screen and the `ScrollView`.
|
|
12
|
+
* When the keyboard appears, the `ScrollView` will only push content by the effective
|
|
13
|
+
* distance (`keyboardHeight - offset`) instead of the full keyboard height.
|
|
14
|
+
*
|
|
15
|
+
* Useful when the input is not at the very bottom of the screen (e.g., above safe area, above
|
|
16
|
+
* bottom tabs, etc. - in this case offset should be equal to the height of the elements between
|
|
17
|
+
* `ScrollView` and bottom of the screen).
|
|
18
|
+
*
|
|
19
|
+
* Default is `0`.
|
|
20
|
+
*/
|
|
21
|
+
offset?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Determines how the chat content should behave when the keyboard appears, specifically whether
|
|
24
|
+
* the scroll view should automatically lift its content to keep it visible above the keyboard.
|
|
25
|
+
*
|
|
26
|
+
* Possible values:
|
|
27
|
+
* - `'always'`: The content always lifts along with the keyboard, ensuring the messages from the bottom part of screen
|
|
28
|
+
* remain visible regardless of the current scroll position. This is the default behavior for most chat applications (used in Telegram).
|
|
29
|
+
* - `'whenAtEnd'`: The content lifts only if the scroll view is at the end (i.e., the last message
|
|
30
|
+
* is visible or near the bottom). This prevents unnecessary adjustments when the user is scrolling
|
|
31
|
+
* through older messages (ChatGPT mobile app behavior).
|
|
32
|
+
* - `'persistent'`: The content always lifts when the keyboard appears (similar to `'always'`), but
|
|
33
|
+
* does not reset (lower) when the keyboard hides. This mimics behaviors where the view remains adjusted
|
|
34
|
+
* after keyboard dismissal to maintain focus on the latest content without shifting back (Claude mobile app behavior).
|
|
35
|
+
* - `'never'`: The content does not lift at all when the keyboard appears. Use this for scenarios
|
|
36
|
+
* when you don't want to disturb user attention with animations (Perplexity mobile app behavior).
|
|
37
|
+
*
|
|
38
|
+
* Default is `'always'`.
|
|
39
|
+
*/
|
|
40
|
+
keyboardLiftBehavior?: KeyboardLiftBehavior;
|
|
41
|
+
/**
|
|
42
|
+
* When `true`, freezes all keyboard-driven layout changes (padding, content offset, scroll position).
|
|
43
|
+
* Useful when dismissing the keyboard to open a bottom sheet — prevents visual disruption
|
|
44
|
+
* while the sheet is visible.
|
|
45
|
+
*
|
|
46
|
+
* Default is `false`.
|
|
47
|
+
*/
|
|
48
|
+
freeze?: boolean;
|
|
49
|
+
} & ScrollViewProps;
|