UNPKG

react-native-keyboard-controller

Version:

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

67 lines (56 loc) 1.69 kB
import { useMemo } from "react"; import { runOnJS, useAnimatedReaction, useDerivedValue, } from "react-native-reanimated"; import { isScrollAtEnd } from "./useChatKeyboard/helpers"; import type { SharedValue } from "react-native-reanimated"; type EndVisibleCallback = (visible: boolean) => void; type Options = { scroll: SharedValue<number>; layout: SharedValue<{ width: number; height: number }>; size: SharedValue<{ width: number; height: number }>; inverted: boolean; onEndVisible?: EndVisibleCallback; }; const hasWorkletHash = (value: unknown): boolean => typeof value === "function" && !!(value as unknown as Record<string, unknown>).__workletHash; export const useEndVisible = ({ scroll, layout, size, inverted, onEndVisible, }: Options) => { const isWorklet = useMemo(() => hasWorkletHash(onEndVisible), [onEndVisible]); const isAtEnd = useDerivedValue(() => { // Wait until the scroll view has been measured to avoid a spurious initial // `true` on a (0,0,0) layout (the helper would otherwise treat unmeasured // state as "at end" because 0 + 0 >= 0 - threshold). if (layout.value.height === 0 || size.value.height === 0) { return null; } return isScrollAtEnd( scroll.value, layout.value.height, size.value.height, inverted, ); }); useAnimatedReaction( () => isAtEnd.value, (current, previous) => { if (current === null || current === previous || !onEndVisible) { return; } if (isWorklet) { onEndVisible(current); } else { runOnJS(onEndVisible)(current); } }, [onEndVisible, isWorklet, inverted], ); };