react-native-keyboard-controller 1.21.1 → 1.21.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/main/java/com/reactnativekeyboardcontroller/views/ClippingScrollViewDecoratorView.kt +18 -1
- package/ios/views/KeyboardExtenderContainerView.swift +4 -1
- package/lib/commonjs/architecture.js +8 -0
- package/lib/commonjs/architecture.js.map +1 -0
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js +25 -16
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/types.js +6 -0
- package/lib/commonjs/components/KeyboardAwareScrollView/types.js.map +1 -0
- package/lib/commonjs/components/KeyboardChatScrollView/index.js +1 -0
- package/lib/commonjs/components/KeyboardChatScrollView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardChatScrollView/useExtraContentPadding/index.js +22 -2
- package/lib/commonjs/components/KeyboardChatScrollView/useExtraContentPadding/index.js.map +1 -1
- package/lib/commonjs/components/ScrollViewWithBottomPadding/styles.js +2 -1
- package/lib/commonjs/components/ScrollViewWithBottomPadding/styles.js.map +1 -1
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/module/architecture.js +2 -0
- package/lib/module/architecture.js.map +1 -0
- package/lib/module/components/KeyboardAwareScrollView/index.js +25 -16
- package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/types.js +2 -0
- package/lib/module/components/KeyboardAwareScrollView/types.js.map +1 -0
- package/lib/module/components/KeyboardChatScrollView/index.js +1 -0
- package/lib/module/components/KeyboardChatScrollView/index.js.map +1 -1
- package/lib/module/components/KeyboardChatScrollView/useExtraContentPadding/index.js +22 -2
- package/lib/module/components/KeyboardChatScrollView/useExtraContentPadding/index.js.map +1 -1
- package/lib/module/components/ScrollViewWithBottomPadding/styles.js +2 -1
- package/lib/module/components/ScrollViewWithBottomPadding/styles.js.map +1 -1
- package/lib/module/components/index.js.map +1 -1
- package/lib/typescript/architecture.d.ts +1 -0
- package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +3 -24
- package/lib/typescript/components/KeyboardAwareScrollView/types.d.ts +17 -0
- package/lib/typescript/components/KeyboardChatScrollView/useExtraContentPadding/index.d.ts +2 -0
- package/lib/typescript/components/ScrollViewWithBottomPadding/styles.d.ts +2 -1
- package/lib/typescript/components/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/architecture.ts +1 -0
- package/src/components/KeyboardAwareScrollView/index.tsx +30 -37
- package/src/components/KeyboardAwareScrollView/types.ts +18 -0
- package/src/components/KeyboardChatScrollView/index.tsx +1 -0
- package/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts +28 -2
- package/src/components/ScrollViewWithBottomPadding/styles.ts +2 -1
- package/src/components/index.ts +1 -1
|
@@ -30,34 +30,15 @@ import ScrollViewWithBottomPadding from "../ScrollViewWithBottomPadding";
|
|
|
30
30
|
import { useSmoothKeyboardHandler } from "./useSmoothKeyboardHandler";
|
|
31
31
|
import { debounce, scrollDistanceWithRespectToSnapPoints } from "./utils";
|
|
32
32
|
|
|
33
|
-
import type {
|
|
34
|
-
import type {
|
|
35
|
-
LayoutChangeEvent,
|
|
36
|
-
ScrollView,
|
|
37
|
-
ScrollViewProps,
|
|
38
|
-
} from "react-native";
|
|
33
|
+
import type { LayoutChangeEvent, ScrollView } from "react-native";
|
|
39
34
|
import type {
|
|
40
35
|
FocusedInputLayoutChangedEvent,
|
|
41
36
|
FocusedInputSelectionChangedEvent,
|
|
37
|
+
KeyboardAwareScrollViewProps,
|
|
38
|
+
KeyboardAwareScrollViewRef,
|
|
42
39
|
NativeEvent,
|
|
43
40
|
} from "react-native-keyboard-controller";
|
|
44
41
|
|
|
45
|
-
export type KeyboardAwareScrollViewProps = {
|
|
46
|
-
/** The distance between the keyboard and the caret inside a focused `TextInput` when the keyboard is shown. Default is `0`. */
|
|
47
|
-
bottomOffset?: number;
|
|
48
|
-
/** Prevents automatic scrolling of the `ScrollView` when the keyboard gets hidden, maintaining the current screen position. Default is `false`. */
|
|
49
|
-
disableScrollOnKeyboardHide?: boolean;
|
|
50
|
-
/** Controls whether this `KeyboardAwareScrollView` instance should take effect. Default is `true`. */
|
|
51
|
-
enabled?: boolean;
|
|
52
|
-
/** Adjusting the bottom spacing of KeyboardAwareScrollView. Default is `0`. */
|
|
53
|
-
extraKeyboardSpace?: number;
|
|
54
|
-
/** Custom component for `ScrollView`. Default is `ScrollView`. */
|
|
55
|
-
ScrollViewComponent?: AnimatedScrollViewComponent;
|
|
56
|
-
} & ScrollViewProps;
|
|
57
|
-
export type KeyboardAwareScrollViewRef = {
|
|
58
|
-
assureFocusedInputVisible: () => void;
|
|
59
|
-
} & ScrollView;
|
|
60
|
-
|
|
61
42
|
// Everything begins from `onStart` handler. This handler is called every time,
|
|
62
43
|
// when keyboard changes its size or when focused `TextInput` was changed. In
|
|
63
44
|
// this handler we are calculating/memoizing values which later will be used
|
|
@@ -151,6 +132,7 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
151
132
|
useSharedValue<FocusedInputSelectionChangedEvent | null>(null);
|
|
152
133
|
const ghostViewSpace = useSharedValue(-1);
|
|
153
134
|
const pendingSelectionForFocus = useSharedValue(false);
|
|
135
|
+
const selectionUpdatedSinceHide = useSharedValue(false);
|
|
154
136
|
const scrollViewPageY = useSharedValue(0);
|
|
155
137
|
|
|
156
138
|
const { height } = useWindowDimensions();
|
|
@@ -339,8 +321,9 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
339
321
|
const latestSelection = lastSelection.value?.selection;
|
|
340
322
|
|
|
341
323
|
lastSelection.value = e;
|
|
324
|
+
selectionUpdatedSinceHide.value = true;
|
|
342
325
|
|
|
343
|
-
if (e.target !== lastTarget) {
|
|
326
|
+
if (e.target !== lastTarget || pendingSelectionForFocus.value) {
|
|
344
327
|
if (pendingSelectionForFocus.value) {
|
|
345
328
|
// selection arrived after onStart - complete the deferred setup
|
|
346
329
|
pendingSelectionForFocus.value = false;
|
|
@@ -416,25 +399,34 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
416
399
|
keyboardWillChangeSize ||
|
|
417
400
|
focusWasChanged
|
|
418
401
|
) {
|
|
419
|
-
syncKeyboardFrame(e);
|
|
420
402
|
// persist scroll value
|
|
421
403
|
scrollPosition.value = position.value;
|
|
422
404
|
// just persist height - later will be used in interpolation
|
|
423
405
|
keyboardHeight.value = e.height;
|
|
406
|
+
// and update keyboard spacer size
|
|
407
|
+
syncKeyboardFrame(e);
|
|
424
408
|
}
|
|
425
409
|
|
|
426
410
|
// focus was changed
|
|
427
411
|
if (focusWasChanged) {
|
|
428
412
|
tag.value = e.target;
|
|
429
413
|
|
|
430
|
-
if (
|
|
431
|
-
|
|
414
|
+
if (
|
|
415
|
+
lastSelection.value?.target === e.target &&
|
|
416
|
+
selectionUpdatedSinceHide.value
|
|
417
|
+
) {
|
|
418
|
+
// fresh selection arrived before onStart - use it to update layout
|
|
432
419
|
updateLayoutFromSelection();
|
|
433
420
|
pendingSelectionForFocus.value = false;
|
|
434
421
|
} else {
|
|
435
|
-
// selection hasn't arrived yet for the new target
|
|
436
|
-
//
|
|
437
|
-
if
|
|
422
|
+
// selection hasn't arrived yet for the new target (iOS 15),
|
|
423
|
+
// or it's stale from previous session (Android refocus same input).
|
|
424
|
+
// Use stale selection as best-effort fallback if available for same target,
|
|
425
|
+
// otherwise fall back to full input layout.
|
|
426
|
+
// Will be corrected if a fresh onSelectionChange arrives.
|
|
427
|
+
if (lastSelection.value?.target === e.target) {
|
|
428
|
+
updateLayoutFromSelection();
|
|
429
|
+
} else if (input.value) {
|
|
438
430
|
layout.value = input.value;
|
|
439
431
|
}
|
|
440
432
|
pendingSelectionForFocus.value = true;
|
|
@@ -483,7 +475,14 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
483
475
|
scrollPosition.value = position.value;
|
|
484
476
|
|
|
485
477
|
if (e.height === 0) {
|
|
486
|
-
|
|
478
|
+
selectionUpdatedSinceHide.value = false;
|
|
479
|
+
} else if (keyboardWillAppear.value) {
|
|
480
|
+
// keyboard fully shown after appearing from hidden state — clear
|
|
481
|
+
// pending flag to prevent leaking into next focus-change session.
|
|
482
|
+
// Only when the keyboard was actually appearing (not a focus switch
|
|
483
|
+
// with same keyboard height), otherwise we'd clear the flag before
|
|
484
|
+
// onSelectionChange has a chance to process it.
|
|
485
|
+
pendingSelectionForFocus.value = false;
|
|
487
486
|
}
|
|
488
487
|
|
|
489
488
|
syncKeyboardFrame(e);
|
|
@@ -552,14 +551,8 @@ const KeyboardAwareScrollView = forwardRef<
|
|
|
552
551
|
[],
|
|
553
552
|
);
|
|
554
553
|
|
|
555
|
-
// animations become choppy when scrolling to the end of the `ScrollView` (when the last input is focused)
|
|
556
|
-
// this happens because the layout recalculates on every frame. To avoid this we slightly increase padding
|
|
557
|
-
// by `+1`. In this way we assure, that `scrollTo` will never scroll to the end, because it uses interpolation
|
|
558
|
-
// from 0 to `keyboardHeight`, and here our padding is `keyboardHeight + 1`. It allows us not to re-run layout
|
|
559
|
-
// re-calculation on every animation frame and it helps to achieve smooth animation.
|
|
560
|
-
// see: https://github.com/kirillzyusko/react-native-keyboard-controller/pull/342
|
|
561
554
|
const padding = useDerivedValue(
|
|
562
|
-
() => (enabled ? currentKeyboardFrameHeight.value
|
|
555
|
+
() => (enabled ? currentKeyboardFrameHeight.value : 0),
|
|
563
556
|
[enabled],
|
|
564
557
|
);
|
|
565
558
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AnimatedScrollViewComponent } from "../ScrollViewWithBottomPadding";
|
|
2
|
+
import type { ScrollView, ScrollViewProps } from "react-native";
|
|
3
|
+
|
|
4
|
+
export type KeyboardAwareScrollViewProps = {
|
|
5
|
+
/** The distance between the keyboard and the caret inside a focused `TextInput` when the keyboard is shown. Default is `0`. */
|
|
6
|
+
bottomOffset?: number;
|
|
7
|
+
/** Prevents automatic scrolling of the `ScrollView` when the keyboard gets hidden, maintaining the current screen position. Default is `false`. */
|
|
8
|
+
disableScrollOnKeyboardHide?: boolean;
|
|
9
|
+
/** Controls whether this `KeyboardAwareScrollView` instance should take effect. Default is `true`. */
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
/** Adjusting the bottom spacing of KeyboardAwareScrollView. Default is `0`. */
|
|
12
|
+
extraKeyboardSpace?: number;
|
|
13
|
+
/** Custom component for `ScrollView`. Default is `ScrollView`. */
|
|
14
|
+
ScrollViewComponent?: AnimatedScrollViewComponent;
|
|
15
|
+
} & ScrollViewProps;
|
|
16
|
+
export type KeyboardAwareScrollViewRef = {
|
|
17
|
+
assureFocusedInputVisible: () => void;
|
|
18
|
+
} & ScrollView;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { Platform } from "react-native";
|
|
1
3
|
import { scrollTo, useAnimatedReaction } from "react-native-reanimated";
|
|
2
4
|
|
|
5
|
+
import { IS_FABRIC } from "../../../architecture";
|
|
3
6
|
import { isScrollAtEnd, shouldShiftContent } from "../useChatKeyboard/helpers";
|
|
4
7
|
|
|
5
8
|
import type { KeyboardLiftBehavior } from "../useChatKeyboard/types";
|
|
@@ -19,6 +22,8 @@ type UseExtraContentPaddingOptions = {
|
|
|
19
22
|
layout: SharedValue<{ width: number; height: number }>;
|
|
20
23
|
/** Total content dimensions. */
|
|
21
24
|
size: SharedValue<{ width: number; height: number }>;
|
|
25
|
+
/** IOS only — when provided, sets contentOffset atomically with contentInset. */
|
|
26
|
+
contentOffsetY?: SharedValue<number>;
|
|
22
27
|
inverted: boolean;
|
|
23
28
|
keyboardLiftBehavior: KeyboardLiftBehavior;
|
|
24
29
|
freeze: boolean;
|
|
@@ -47,11 +52,32 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void {
|
|
|
47
52
|
scroll,
|
|
48
53
|
layout,
|
|
49
54
|
size,
|
|
55
|
+
contentOffsetY,
|
|
50
56
|
inverted,
|
|
51
57
|
keyboardLiftBehavior,
|
|
52
58
|
freeze,
|
|
53
59
|
} = options;
|
|
54
60
|
|
|
61
|
+
const scrollToTarget = useCallback(
|
|
62
|
+
(target: number) => {
|
|
63
|
+
"worklet";
|
|
64
|
+
|
|
65
|
+
if (contentOffsetY && IS_FABRIC) {
|
|
66
|
+
// eslint-disable-next-line react-compiler/react-compiler
|
|
67
|
+
contentOffsetY.value = target;
|
|
68
|
+
} else if (Platform.OS === "android") {
|
|
69
|
+
// Defer scrollTo so the animatedProps inset commit lands first;
|
|
70
|
+
// otherwise the native ScrollView clamps to the old range.
|
|
71
|
+
requestAnimationFrame(() => {
|
|
72
|
+
scrollTo(scrollViewRef, 0, target, false);
|
|
73
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
scrollTo(scrollViewRef, 0, target, false);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
[scrollViewRef, contentOffsetY],
|
|
79
|
+
);
|
|
80
|
+
|
|
55
81
|
useAnimatedReaction(
|
|
56
82
|
() => extraContentPadding.value,
|
|
57
83
|
(current, previous) => {
|
|
@@ -104,7 +130,7 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void {
|
|
|
104
130
|
if (inverted) {
|
|
105
131
|
const target = Math.max(scroll.value - effectiveDelta, -currentTotal);
|
|
106
132
|
|
|
107
|
-
|
|
133
|
+
scrollToTarget(target);
|
|
108
134
|
} else {
|
|
109
135
|
const maxScroll = Math.max(
|
|
110
136
|
size.value.height - layout.value.height + currentTotal,
|
|
@@ -112,7 +138,7 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void {
|
|
|
112
138
|
);
|
|
113
139
|
const target = Math.min(scroll.value + effectiveDelta, maxScroll);
|
|
114
140
|
|
|
115
|
-
|
|
141
|
+
scrollToTarget(target);
|
|
116
142
|
}
|
|
117
143
|
},
|
|
118
144
|
[inverted, keyboardLiftBehavior, freeze],
|
package/src/components/index.ts
CHANGED
|
@@ -11,6 +11,6 @@ export type { KeyboardStickyViewProps } from "./KeyboardStickyView";
|
|
|
11
11
|
export type {
|
|
12
12
|
KeyboardAwareScrollViewProps,
|
|
13
13
|
KeyboardAwareScrollViewRef,
|
|
14
|
-
} from "./KeyboardAwareScrollView";
|
|
14
|
+
} from "./KeyboardAwareScrollView/types";
|
|
15
15
|
export type { KeyboardToolbarProps } from "./KeyboardToolbar";
|
|
16
16
|
export type { KeyboardChatScrollViewProps } from "./KeyboardChatScrollView/types";
|