UNPKG

react-native-keyboard-controller

Version:

Keyboard manager which works in identical way on both iOS and Android

92 lines (89 loc) 3.22 kB
import { useCallback } from "react"; import { Platform } from "react-native"; import { scrollTo, useAnimatedReaction } from "react-native-reanimated"; import { IS_FABRIC } from "../../../architecture"; import { isScrollAtEnd, shouldShiftContent } from "../useChatKeyboard/helpers"; /** * Hook that reacts to `extraContentPadding` changes and conditionally * adjusts the scroll position using `scrollTo` on both iOS and Android. * * Padding extension (scrollable range) is handled externally via a * `useDerivedValue` that sums keyboard padding + extra content padding. * This hook only handles the scroll correction. * * @param options - Configuration and shared values. * @example * ```tsx * useExtraContentPadding({ scrollViewRef, extraContentPadding, ... }); * ``` */ function useExtraContentPadding(options) { const { scrollViewRef, extraContentPadding, keyboardPadding, blankSpace, scroll, layout, size, contentOffsetY, inverted, keyboardLiftBehavior, freeze } = options; const scrollToTarget = useCallback(target => { "worklet"; if (contentOffsetY && IS_FABRIC) { // eslint-disable-next-line react-compiler/react-compiler contentOffsetY.value = target; } else if (Platform.OS === "android") { // Defer scrollTo so the animatedProps inset commit lands first; // otherwise the native ScrollView clamps to the old range. requestAnimationFrame(() => { // check that view is still mounted and ref is actual // otherwise it may lead to a crash if (!scrollViewRef()) { return; } scrollTo(scrollViewRef, 0, target, false); }); } else { scrollTo(scrollViewRef, 0, target, false); } }, [scrollViewRef, contentOffsetY]); useAnimatedReaction(() => extraContentPadding.value, (current, previous) => { if (freeze.value || previous === null) { return; } const rawDelta = current - previous; if (rawDelta === 0) { return; } // Compute effective delta considering blankSpace floor const previousTotal = Math.max(blankSpace.value, keyboardPadding.value + previous); const currentTotal = Math.max(blankSpace.value, keyboardPadding.value + current); const effectiveDelta = currentTotal - previousTotal; if (effectiveDelta === 0) { // blankSpace absorbed the change return; } const atEnd = isScrollAtEnd(scroll.value, layout.value.height, size.value.height, inverted); // "persistent": scroll on grow, hold position on shrink (unless at end) if (keyboardLiftBehavior === "persistent" && effectiveDelta < 0 && !atEnd) { return; } if (!shouldShiftContent(keyboardLiftBehavior, atEnd)) { return; } if (inverted) { const target = Math.max(scroll.value - effectiveDelta, -currentTotal); scrollToTarget(target); } else { const maxScroll = Math.max(size.value.height - layout.value.height + currentTotal, 0); const target = Math.min(scroll.value + effectiveDelta, maxScroll); scrollToTarget(target); } }, [inverted, keyboardLiftBehavior]); } export { useExtraContentPadding }; //# sourceMappingURL=index.js.map