UNPKG

react-native-keyboard-controller

Version:

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

109 lines (93 loc) 3.45 kB
import { useRef } from "react"; import { Animated } from "react-native"; import { findNodeHandle } from "./utils/findNodeHandle"; import type { EventHandlerProcessed } from "react-native-reanimated"; type ComponentOrHandle = Parameters<typeof findNodeHandle>[0]; type WorkletHandler = { registerForEvents: (viewTag: number) => void; unregisterFromEvents: (viewTag: number) => void; }; type WorkletHandlerOrWorkletHandlerObject = | WorkletHandler | { workletEventHandler: WorkletHandler; }; /** * An internal hook that helps to register workletized event handlers. * * @param viewTagRef - Ref to the view that produces events. * @returns A function that registers supplied event handlers. * @example * ```ts * const setKeyboardHandlers = useEventHandlerRegistration<KeyboardHandler>( * keyboardEventsMap, * viewTagRef, * ); * ``` */ export function useEventHandlerRegistration( viewTagRef: React.MutableRefObject<ComponentOrHandle>, ) { const onRegisterHandler = (handler: EventHandlerProcessed<never, never>) => { const currentHandler = handler as unknown as WorkletHandlerOrWorkletHandlerObject; const attachWorkletHandlers = () => { const viewTag = findNodeHandle(viewTagRef.current); if (__DEV__ && !viewTag) { console.warn( "Can not attach worklet handlers for `react-native-keyboard-controller` because view tag can not be resolved. Be sure that `KeyboardProvider` is fully mounted before registering handlers. If you think it is a bug in library, please open an issue.", ); } if (viewTag) { if ("workletEventHandler" in currentHandler) { currentHandler.workletEventHandler.registerForEvents(viewTag); } else { currentHandler.registerForEvents(viewTag); } } }; if (viewTagRef.current) { attachWorkletHandlers(); } else { // view may not be mounted yet - defer registration until call-stack becomes empty queueMicrotask(attachWorkletHandlers); } return () => { const viewTag = findNodeHandle(viewTagRef.current); if (viewTag) { if ("workletEventHandler" in currentHandler) { currentHandler.workletEventHandler.unregisterFromEvents(viewTag); } else { currentHandler.unregisterFromEvents(viewTag); } } }; }; return onRegisterHandler; } /** * TS variant of `useAnimatedValue` hook which is added in RN 0.71 * A better alternative of storing animated values in refs, since * it doesn't recreate a new `Animated.Value` object on every re-render * and therefore consumes less memory. We can not use a variant from * RN, since this library supports earlier versions of RN. * * @param initialValue - Initial value of the animated value (numeric). * @param config - Additional {@link Animated.AnimatedConfig|configuration} for the animated value. * @returns Properly memoized {@link Animated.Value|Animated} value. * @see https://github.com/facebook/react-native/commit/e22217fe8b9455e32695f88ca835e11442b0a937 * @example * ```ts * const progress = useAnimatedValue(0); * ``` */ export function useAnimatedValue( initialValue: number, config?: Animated.AnimatedConfig, ): Animated.Value { const ref = useRef<Animated.Value | null>(null); if (ref.current === null) { ref.current = new Animated.Value(initialValue, config); } return ref.current; }