react-native-keyboard-controller 1.22.1 → 1.22.2

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.
@@ -137,21 +137,25 @@ class KeyboardGestureAreaReactViewGroup(
137
137
  if (moveBy != 0) {
138
138
  controller.insetBy(moveBy)
139
139
  }
140
- } else if (
141
- !controller.isInsetAnimationRequestPending() &&
142
- shouldStartRequest(
143
- dy = dy,
144
- imeVisible =
145
- ViewCompat
146
- .getRootWindowInsets(this)
147
- ?.isVisible(WindowInsetsCompat.Type.ime()) == true,
148
- )
149
- ) {
150
- // If we don't currently have control (and a request isn't pending),
151
- // the IME is not shown, the user is scrolling up, and the view can't
152
- // scroll up any more (i.e. over-scrolling), we can start to control
153
- // the IME insets
154
- controller.startControlRequest(this)
140
+ } else if (!controller.isInsetAnimationRequestPending()) {
141
+ val rootInsets = ViewCompat.getRootWindowInsets(this)
142
+ val moveBy =
143
+ this.interpolator.interpolate(
144
+ dy.roundToInt(),
145
+ this.getWindowHeight() - event.rawY.toInt(),
146
+ rootInsets?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0,
147
+ offset,
148
+ )
149
+
150
+ if (
151
+ moveBy != 0 &&
152
+ shouldStartRequest(
153
+ dy = dy,
154
+ imeVisible = rootInsets?.isVisible(WindowInsetsCompat.Type.ime()) == true,
155
+ )
156
+ ) {
157
+ controller.startControlRequest(this)
158
+ }
155
159
  }
156
160
 
157
161
  // Lastly we record the event X, Y, and view's Y window position, for the
@@ -9,6 +9,8 @@ var _reactNative = require("react-native");
9
9
  var _reactNativeReanimated = require("react-native-reanimated");
10
10
  var _architecture = require("../../../architecture");
11
11
  var _helpers = require("../useChatKeyboard/helpers");
12
+ const OS = _reactNative.Platform.OS;
13
+
12
14
  /**
13
15
  * Hook that reacts to `extraContentPadding` changes and conditionally
14
16
  * adjusts the scroll position using `scrollTo` on both iOS and Android.
@@ -43,7 +45,7 @@ function useExtraContentPadding(options) {
43
45
  if (contentOffsetY && _architecture.IS_FABRIC) {
44
46
  // eslint-disable-next-line react-compiler/react-compiler
45
47
  contentOffsetY.value = target;
46
- } else if (_reactNative.Platform.OS === "android") {
48
+ } else if (OS === "android") {
47
49
  // Defer scrollTo so the animatedProps inset commit lands first;
48
50
  // otherwise the native ScrollView clamps to the old range.
49
51
  requestAnimationFrame(() => {
@@ -1 +1 @@
1
- {"version":3,"names":["_react","require","_reactNative","_reactNativeReanimated","_architecture","_helpers","useExtraContentPadding","options","scrollViewRef","extraContentPadding","keyboardPadding","blankSpace","scroll","layout","size","contentOffsetY","inverted","keyboardLiftBehavior","freeze","scrollToTarget","useCallback","target","IS_FABRIC","value","Platform","OS","requestAnimationFrame","scrollTo","useAnimatedReaction","current","previous","rawDelta","previousTotal","Math","max","currentTotal","effectiveDelta","atEnd","isScrollAtEnd","height","shouldShiftContent","maxScroll","min"],"sources":["index.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { Platform } from \"react-native\";\nimport { scrollTo, useAnimatedReaction } from \"react-native-reanimated\";\n\nimport { IS_FABRIC } from \"../../../architecture\";\nimport { isScrollAtEnd, shouldShiftContent } from \"../useChatKeyboard/helpers\";\n\nimport type { KeyboardLiftBehavior } from \"../useChatKeyboard/types\";\nimport type { AnimatedRef, SharedValue } from \"react-native-reanimated\";\nimport type Reanimated from \"react-native-reanimated\";\n\ntype UseExtraContentPaddingOptions = {\n scrollViewRef: AnimatedRef<Reanimated.ScrollView>;\n extraContentPadding: SharedValue<number>;\n /** Keyboard-only padding from useChatKeyboard — used to compute total padding for clamping. */\n keyboardPadding: SharedValue<number>;\n /** Minimum inset floor — used to absorb keyboard and extraContentPadding changes. */\n blankSpace: SharedValue<number>;\n /** Current vertical scroll offset. */\n scroll: SharedValue<number>;\n /** Visible viewport dimensions. */\n layout: SharedValue<{ width: number; height: number }>;\n /** Total content dimensions. */\n size: SharedValue<{ width: number; height: number }>;\n /** IOS only — when provided, sets contentOffset atomically with contentInset. */\n contentOffsetY?: SharedValue<number>;\n inverted: boolean;\n keyboardLiftBehavior: KeyboardLiftBehavior;\n freeze: SharedValue<boolean>;\n};\n\n/**\n * Hook that reacts to `extraContentPadding` changes and conditionally\n * adjusts the scroll position using `scrollTo` on both iOS and Android.\n *\n * Padding extension (scrollable range) is handled externally via a\n * `useDerivedValue` that sums keyboard padding + extra content padding.\n * This hook only handles the scroll correction.\n *\n * @param options - Configuration and shared values.\n * @example\n * ```tsx\n * useExtraContentPadding({ scrollViewRef, extraContentPadding, ... });\n * ```\n */\nfunction useExtraContentPadding(options: UseExtraContentPaddingOptions): void {\n const {\n scrollViewRef,\n extraContentPadding,\n keyboardPadding,\n blankSpace,\n scroll,\n layout,\n size,\n contentOffsetY,\n inverted,\n keyboardLiftBehavior,\n freeze,\n } = options;\n\n const scrollToTarget = useCallback(\n (target: number) => {\n \"worklet\";\n\n if (contentOffsetY && IS_FABRIC) {\n // eslint-disable-next-line react-compiler/react-compiler\n contentOffsetY.value = target;\n } else if (Platform.OS === \"android\") {\n // Defer scrollTo so the animatedProps inset commit lands first;\n // otherwise the native ScrollView clamps to the old range.\n requestAnimationFrame(() => {\n // check that view is still mounted and ref is actual\n // otherwise it may lead to a crash\n if (!scrollViewRef()) {\n return;\n }\n scrollTo(scrollViewRef, 0, target, false);\n });\n } else {\n scrollTo(scrollViewRef, 0, target, false);\n }\n },\n [scrollViewRef, contentOffsetY],\n );\n\n useAnimatedReaction(\n () => extraContentPadding.value,\n (current, previous) => {\n if (freeze.value || previous === null) {\n return;\n }\n\n const rawDelta = current - previous;\n\n if (rawDelta === 0) {\n return;\n }\n\n // Compute effective delta considering blankSpace floor\n const previousTotal = Math.max(\n blankSpace.value,\n keyboardPadding.value + previous,\n );\n const currentTotal = Math.max(\n blankSpace.value,\n keyboardPadding.value + current,\n );\n const effectiveDelta = currentTotal - previousTotal;\n\n if (effectiveDelta === 0) {\n // blankSpace absorbed the change\n return;\n }\n\n const atEnd = isScrollAtEnd(\n scroll.value,\n layout.value.height,\n size.value.height,\n inverted,\n );\n\n // \"persistent\": scroll on grow, hold position on shrink (unless at end)\n if (\n keyboardLiftBehavior === \"persistent\" &&\n effectiveDelta < 0 &&\n !atEnd\n ) {\n return;\n }\n\n if (!shouldShiftContent(keyboardLiftBehavior, atEnd)) {\n return;\n }\n\n if (inverted) {\n const target = Math.max(scroll.value - effectiveDelta, -currentTotal);\n\n scrollToTarget(target);\n } else {\n const maxScroll = Math.max(\n size.value.height - layout.value.height + currentTotal,\n 0,\n );\n const target = Math.min(scroll.value + effectiveDelta, maxScroll);\n\n scrollToTarget(target);\n }\n },\n [inverted, keyboardLiftBehavior],\n );\n}\n\nexport { useExtraContentPadding };\nexport type { UseExtraContentPaddingOptions };\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_react","require","_reactNative","_reactNativeReanimated","_architecture","_helpers","OS","Platform","useExtraContentPadding","options","scrollViewRef","extraContentPadding","keyboardPadding","blankSpace","scroll","layout","size","contentOffsetY","inverted","keyboardLiftBehavior","freeze","scrollToTarget","useCallback","target","IS_FABRIC","value","requestAnimationFrame","scrollTo","useAnimatedReaction","current","previous","rawDelta","previousTotal","Math","max","currentTotal","effectiveDelta","atEnd","isScrollAtEnd","height","shouldShiftContent","maxScroll","min"],"sources":["index.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { Platform } from \"react-native\";\nimport { scrollTo, useAnimatedReaction } from \"react-native-reanimated\";\n\nimport { IS_FABRIC } from \"../../../architecture\";\nimport { isScrollAtEnd, shouldShiftContent } from \"../useChatKeyboard/helpers\";\n\nimport type { KeyboardLiftBehavior } from \"../useChatKeyboard/types\";\nimport type { AnimatedRef, SharedValue } from \"react-native-reanimated\";\nimport type Reanimated from \"react-native-reanimated\";\n\ntype UseExtraContentPaddingOptions = {\n scrollViewRef: AnimatedRef<Reanimated.ScrollView>;\n extraContentPadding: SharedValue<number>;\n /** Keyboard-only padding from useChatKeyboard — used to compute total padding for clamping. */\n keyboardPadding: SharedValue<number>;\n /** Minimum inset floor — used to absorb keyboard and extraContentPadding changes. */\n blankSpace: SharedValue<number>;\n /** Current vertical scroll offset. */\n scroll: SharedValue<number>;\n /** Visible viewport dimensions. */\n layout: SharedValue<{ width: number; height: number }>;\n /** Total content dimensions. */\n size: SharedValue<{ width: number; height: number }>;\n /** IOS only — when provided, sets contentOffset atomically with contentInset. */\n contentOffsetY?: SharedValue<number>;\n inverted: boolean;\n keyboardLiftBehavior: KeyboardLiftBehavior;\n freeze: SharedValue<boolean>;\n};\n\nconst OS = Platform.OS;\n\n/**\n * Hook that reacts to `extraContentPadding` changes and conditionally\n * adjusts the scroll position using `scrollTo` on both iOS and Android.\n *\n * Padding extension (scrollable range) is handled externally via a\n * `useDerivedValue` that sums keyboard padding + extra content padding.\n * This hook only handles the scroll correction.\n *\n * @param options - Configuration and shared values.\n * @example\n * ```tsx\n * useExtraContentPadding({ scrollViewRef, extraContentPadding, ... });\n * ```\n */\nfunction useExtraContentPadding(options: UseExtraContentPaddingOptions): void {\n const {\n scrollViewRef,\n extraContentPadding,\n keyboardPadding,\n blankSpace,\n scroll,\n layout,\n size,\n contentOffsetY,\n inverted,\n keyboardLiftBehavior,\n freeze,\n } = options;\n\n const scrollToTarget = useCallback(\n (target: number) => {\n \"worklet\";\n\n if (contentOffsetY && IS_FABRIC) {\n // eslint-disable-next-line react-compiler/react-compiler\n contentOffsetY.value = target;\n } else if (OS === \"android\") {\n // Defer scrollTo so the animatedProps inset commit lands first;\n // otherwise the native ScrollView clamps to the old range.\n requestAnimationFrame(() => {\n // check that view is still mounted and ref is actual\n // otherwise it may lead to a crash\n if (!scrollViewRef()) {\n return;\n }\n scrollTo(scrollViewRef, 0, target, false);\n });\n } else {\n scrollTo(scrollViewRef, 0, target, false);\n }\n },\n [scrollViewRef, contentOffsetY],\n );\n\n useAnimatedReaction(\n () => extraContentPadding.value,\n (current, previous) => {\n if (freeze.value || previous === null) {\n return;\n }\n\n const rawDelta = current - previous;\n\n if (rawDelta === 0) {\n return;\n }\n\n // Compute effective delta considering blankSpace floor\n const previousTotal = Math.max(\n blankSpace.value,\n keyboardPadding.value + previous,\n );\n const currentTotal = Math.max(\n blankSpace.value,\n keyboardPadding.value + current,\n );\n const effectiveDelta = currentTotal - previousTotal;\n\n if (effectiveDelta === 0) {\n // blankSpace absorbed the change\n return;\n }\n\n const atEnd = isScrollAtEnd(\n scroll.value,\n layout.value.height,\n size.value.height,\n inverted,\n );\n\n // \"persistent\": scroll on grow, hold position on shrink (unless at end)\n if (\n keyboardLiftBehavior === \"persistent\" &&\n effectiveDelta < 0 &&\n !atEnd\n ) {\n return;\n }\n\n if (!shouldShiftContent(keyboardLiftBehavior, atEnd)) {\n return;\n }\n\n if (inverted) {\n const target = Math.max(scroll.value - effectiveDelta, -currentTotal);\n\n scrollToTarget(target);\n } else {\n const maxScroll = Math.max(\n size.value.height - layout.value.height + currentTotal,\n 0,\n );\n const target = Math.min(scroll.value + effectiveDelta, maxScroll);\n\n scrollToTarget(target);\n }\n },\n [inverted, keyboardLiftBehavior],\n );\n}\n\nexport { useExtraContentPadding };\nexport type { UseExtraContentPaddingOptions };\n"],"mappings":"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","ignoreList":[]}
@@ -3,6 +3,8 @@ import { Platform } from "react-native";
3
3
  import { scrollTo, useAnimatedReaction } from "react-native-reanimated";
4
4
  import { IS_FABRIC } from "../../../architecture";
5
5
  import { isScrollAtEnd, shouldShiftContent } from "../useChatKeyboard/helpers";
6
+ const OS = Platform.OS;
7
+
6
8
  /**
7
9
  * Hook that reacts to `extraContentPadding` changes and conditionally
8
10
  * adjusts the scroll position using `scrollTo` on both iOS and Android.
@@ -37,7 +39,7 @@ function useExtraContentPadding(options) {
37
39
  if (contentOffsetY && IS_FABRIC) {
38
40
  // eslint-disable-next-line react-compiler/react-compiler
39
41
  contentOffsetY.value = target;
40
- } else if (Platform.OS === "android") {
42
+ } else if (OS === "android") {
41
43
  // Defer scrollTo so the animatedProps inset commit lands first;
42
44
  // otherwise the native ScrollView clamps to the old range.
43
45
  requestAnimationFrame(() => {
@@ -1 +1 @@
1
- {"version":3,"names":["useCallback","Platform","scrollTo","useAnimatedReaction","IS_FABRIC","isScrollAtEnd","shouldShiftContent","useExtraContentPadding","options","scrollViewRef","extraContentPadding","keyboardPadding","blankSpace","scroll","layout","size","contentOffsetY","inverted","keyboardLiftBehavior","freeze","scrollToTarget","target","value","OS","requestAnimationFrame","current","previous","rawDelta","previousTotal","Math","max","currentTotal","effectiveDelta","atEnd","height","maxScroll","min"],"sources":["index.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { Platform } from \"react-native\";\nimport { scrollTo, useAnimatedReaction } from \"react-native-reanimated\";\n\nimport { IS_FABRIC } from \"../../../architecture\";\nimport { isScrollAtEnd, shouldShiftContent } from \"../useChatKeyboard/helpers\";\n\nimport type { KeyboardLiftBehavior } from \"../useChatKeyboard/types\";\nimport type { AnimatedRef, SharedValue } from \"react-native-reanimated\";\nimport type Reanimated from \"react-native-reanimated\";\n\ntype UseExtraContentPaddingOptions = {\n scrollViewRef: AnimatedRef<Reanimated.ScrollView>;\n extraContentPadding: SharedValue<number>;\n /** Keyboard-only padding from useChatKeyboard — used to compute total padding for clamping. */\n keyboardPadding: SharedValue<number>;\n /** Minimum inset floor — used to absorb keyboard and extraContentPadding changes. */\n blankSpace: SharedValue<number>;\n /** Current vertical scroll offset. */\n scroll: SharedValue<number>;\n /** Visible viewport dimensions. */\n layout: SharedValue<{ width: number; height: number }>;\n /** Total content dimensions. */\n size: SharedValue<{ width: number; height: number }>;\n /** IOS only — when provided, sets contentOffset atomically with contentInset. */\n contentOffsetY?: SharedValue<number>;\n inverted: boolean;\n keyboardLiftBehavior: KeyboardLiftBehavior;\n freeze: SharedValue<boolean>;\n};\n\n/**\n * Hook that reacts to `extraContentPadding` changes and conditionally\n * adjusts the scroll position using `scrollTo` on both iOS and Android.\n *\n * Padding extension (scrollable range) is handled externally via a\n * `useDerivedValue` that sums keyboard padding + extra content padding.\n * This hook only handles the scroll correction.\n *\n * @param options - Configuration and shared values.\n * @example\n * ```tsx\n * useExtraContentPadding({ scrollViewRef, extraContentPadding, ... });\n * ```\n */\nfunction useExtraContentPadding(options: UseExtraContentPaddingOptions): void {\n const {\n scrollViewRef,\n extraContentPadding,\n keyboardPadding,\n blankSpace,\n scroll,\n layout,\n size,\n contentOffsetY,\n inverted,\n keyboardLiftBehavior,\n freeze,\n } = options;\n\n const scrollToTarget = useCallback(\n (target: number) => {\n \"worklet\";\n\n if (contentOffsetY && IS_FABRIC) {\n // eslint-disable-next-line react-compiler/react-compiler\n contentOffsetY.value = target;\n } else if (Platform.OS === \"android\") {\n // Defer scrollTo so the animatedProps inset commit lands first;\n // otherwise the native ScrollView clamps to the old range.\n requestAnimationFrame(() => {\n // check that view is still mounted and ref is actual\n // otherwise it may lead to a crash\n if (!scrollViewRef()) {\n return;\n }\n scrollTo(scrollViewRef, 0, target, false);\n });\n } else {\n scrollTo(scrollViewRef, 0, target, false);\n }\n },\n [scrollViewRef, contentOffsetY],\n );\n\n useAnimatedReaction(\n () => extraContentPadding.value,\n (current, previous) => {\n if (freeze.value || previous === null) {\n return;\n }\n\n const rawDelta = current - previous;\n\n if (rawDelta === 0) {\n return;\n }\n\n // Compute effective delta considering blankSpace floor\n const previousTotal = Math.max(\n blankSpace.value,\n keyboardPadding.value + previous,\n );\n const currentTotal = Math.max(\n blankSpace.value,\n keyboardPadding.value + current,\n );\n const effectiveDelta = currentTotal - previousTotal;\n\n if (effectiveDelta === 0) {\n // blankSpace absorbed the change\n return;\n }\n\n const atEnd = isScrollAtEnd(\n scroll.value,\n layout.value.height,\n size.value.height,\n inverted,\n );\n\n // \"persistent\": scroll on grow, hold position on shrink (unless at end)\n if (\n keyboardLiftBehavior === \"persistent\" &&\n effectiveDelta < 0 &&\n !atEnd\n ) {\n return;\n }\n\n if (!shouldShiftContent(keyboardLiftBehavior, atEnd)) {\n return;\n }\n\n if (inverted) {\n const target = Math.max(scroll.value - effectiveDelta, -currentTotal);\n\n scrollToTarget(target);\n } else {\n const maxScroll = Math.max(\n size.value.height - layout.value.height + currentTotal,\n 0,\n );\n const target = Math.min(scroll.value + effectiveDelta, maxScroll);\n\n scrollToTarget(target);\n }\n },\n [inverted, keyboardLiftBehavior],\n );\n}\n\nexport { useExtraContentPadding };\nexport type { UseExtraContentPaddingOptions };\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["useCallback","Platform","scrollTo","useAnimatedReaction","IS_FABRIC","isScrollAtEnd","shouldShiftContent","OS","useExtraContentPadding","options","scrollViewRef","extraContentPadding","keyboardPadding","blankSpace","scroll","layout","size","contentOffsetY","inverted","keyboardLiftBehavior","freeze","scrollToTarget","target","value","requestAnimationFrame","current","previous","rawDelta","previousTotal","Math","max","currentTotal","effectiveDelta","atEnd","height","maxScroll","min"],"sources":["index.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { Platform } from \"react-native\";\nimport { scrollTo, useAnimatedReaction } from \"react-native-reanimated\";\n\nimport { IS_FABRIC } from \"../../../architecture\";\nimport { isScrollAtEnd, shouldShiftContent } from \"../useChatKeyboard/helpers\";\n\nimport type { KeyboardLiftBehavior } from \"../useChatKeyboard/types\";\nimport type { AnimatedRef, SharedValue } from \"react-native-reanimated\";\nimport type Reanimated from \"react-native-reanimated\";\n\ntype UseExtraContentPaddingOptions = {\n scrollViewRef: AnimatedRef<Reanimated.ScrollView>;\n extraContentPadding: SharedValue<number>;\n /** Keyboard-only padding from useChatKeyboard — used to compute total padding for clamping. */\n keyboardPadding: SharedValue<number>;\n /** Minimum inset floor — used to absorb keyboard and extraContentPadding changes. */\n blankSpace: SharedValue<number>;\n /** Current vertical scroll offset. */\n scroll: SharedValue<number>;\n /** Visible viewport dimensions. */\n layout: SharedValue<{ width: number; height: number }>;\n /** Total content dimensions. */\n size: SharedValue<{ width: number; height: number }>;\n /** IOS only — when provided, sets contentOffset atomically with contentInset. */\n contentOffsetY?: SharedValue<number>;\n inverted: boolean;\n keyboardLiftBehavior: KeyboardLiftBehavior;\n freeze: SharedValue<boolean>;\n};\n\nconst OS = Platform.OS;\n\n/**\n * Hook that reacts to `extraContentPadding` changes and conditionally\n * adjusts the scroll position using `scrollTo` on both iOS and Android.\n *\n * Padding extension (scrollable range) is handled externally via a\n * `useDerivedValue` that sums keyboard padding + extra content padding.\n * This hook only handles the scroll correction.\n *\n * @param options - Configuration and shared values.\n * @example\n * ```tsx\n * useExtraContentPadding({ scrollViewRef, extraContentPadding, ... });\n * ```\n */\nfunction useExtraContentPadding(options: UseExtraContentPaddingOptions): void {\n const {\n scrollViewRef,\n extraContentPadding,\n keyboardPadding,\n blankSpace,\n scroll,\n layout,\n size,\n contentOffsetY,\n inverted,\n keyboardLiftBehavior,\n freeze,\n } = options;\n\n const scrollToTarget = useCallback(\n (target: number) => {\n \"worklet\";\n\n if (contentOffsetY && IS_FABRIC) {\n // eslint-disable-next-line react-compiler/react-compiler\n contentOffsetY.value = target;\n } else if (OS === \"android\") {\n // Defer scrollTo so the animatedProps inset commit lands first;\n // otherwise the native ScrollView clamps to the old range.\n requestAnimationFrame(() => {\n // check that view is still mounted and ref is actual\n // otherwise it may lead to a crash\n if (!scrollViewRef()) {\n return;\n }\n scrollTo(scrollViewRef, 0, target, false);\n });\n } else {\n scrollTo(scrollViewRef, 0, target, false);\n }\n },\n [scrollViewRef, contentOffsetY],\n );\n\n useAnimatedReaction(\n () => extraContentPadding.value,\n (current, previous) => {\n if (freeze.value || previous === null) {\n return;\n }\n\n const rawDelta = current - previous;\n\n if (rawDelta === 0) {\n return;\n }\n\n // Compute effective delta considering blankSpace floor\n const previousTotal = Math.max(\n blankSpace.value,\n keyboardPadding.value + previous,\n );\n const currentTotal = Math.max(\n blankSpace.value,\n keyboardPadding.value + current,\n );\n const effectiveDelta = currentTotal - previousTotal;\n\n if (effectiveDelta === 0) {\n // blankSpace absorbed the change\n return;\n }\n\n const atEnd = isScrollAtEnd(\n scroll.value,\n layout.value.height,\n size.value.height,\n inverted,\n );\n\n // \"persistent\": scroll on grow, hold position on shrink (unless at end)\n if (\n keyboardLiftBehavior === \"persistent\" &&\n effectiveDelta < 0 &&\n !atEnd\n ) {\n return;\n }\n\n if (!shouldShiftContent(keyboardLiftBehavior, atEnd)) {\n return;\n }\n\n if (inverted) {\n const target = Math.max(scroll.value - effectiveDelta, -currentTotal);\n\n scrollToTarget(target);\n } else {\n const maxScroll = Math.max(\n size.value.height - layout.value.height + currentTotal,\n 0,\n );\n const target = Math.min(scroll.value + effectiveDelta, maxScroll);\n\n scrollToTarget(target);\n }\n },\n [inverted, keyboardLiftBehavior],\n );\n}\n\nexport { useExtraContentPadding };\nexport type { UseExtraContentPaddingOptions };\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-keyboard-controller",
3
- "version": "1.22.1",
3
+ "version": "1.22.2",
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",
@@ -29,6 +29,8 @@ type UseExtraContentPaddingOptions = {
29
29
  freeze: SharedValue<boolean>;
30
30
  };
31
31
 
32
+ const OS = Platform.OS;
33
+
32
34
  /**
33
35
  * Hook that reacts to `extraContentPadding` changes and conditionally
34
36
  * adjusts the scroll position using `scrollTo` on both iOS and Android.
@@ -65,7 +67,7 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void {
65
67
  if (contentOffsetY && IS_FABRIC) {
66
68
  // eslint-disable-next-line react-compiler/react-compiler
67
69
  contentOffsetY.value = target;
68
- } else if (Platform.OS === "android") {
70
+ } else if (OS === "android") {
69
71
  // Defer scrollTo so the animatedProps inset commit lands first;
70
72
  // otherwise the native ScrollView clamps to the old range.
71
73
  requestAnimationFrame(() => {