UNPKG

react-native-gesture-handler

Version:

Declarative API exposing native platform touch and gesture system to React Native

120 lines (99 loc) 3 kB
import { Reanimated } from '../../../handlers/gestures/reanimatedWrapper'; import { NativeProxy } from '../../NativeProxy'; import type { BaseGestureConfig, SharedValue, SharedValueOrT, } from '../../types'; import { HandlerCallbacks } from './propsWhiteList'; // Variant of djb2 hash function. // Taken from https://gist.github.com/eplawless/52813b1d8ad9af510d85?permalink_comment_id=3367765#gistcomment-3367765 function hash(str: string) { 'worklet'; const len = str.length; let h = 5381; for (let i = 0; i < len; i++) { h = (h * 33) ^ str.charCodeAt(i); } return h >>> 0; } export const SHARED_VALUE_OFFSET = 1.618; // Don't transfer entire NativeProxy to the UI thread const { updateGestureHandlerConfig } = NativeProxy; export function bindSharedValues< TConfig, THandlerData, TExtendedHandlerData extends THandlerData, >( config: BaseGestureConfig<TConfig, THandlerData, TExtendedHandlerData>, handlerTag: number ) { if (Reanimated === undefined) { return; } const baseListenerId = handlerTag + SHARED_VALUE_OFFSET; const { shouldUseReanimatedDetector } = config; const attachListener = (sharedValue: SharedValue, configKey: string) => { 'worklet'; const keyHash = hash(configKey); const listenerId = baseListenerId + keyHash; sharedValue.addListener(listenerId, (value) => { updateGestureHandlerConfig( handlerTag, configKey === 'runOnJS' ? { dispatchesReanimatedEvents: shouldUseReanimatedDetector && !value, } : { [configKey]: value } ); }); }; for (const [key, maybeSharedValue] of Object.entries(config)) { if (!Reanimated.isSharedValue(maybeSharedValue)) { continue; } Reanimated.runOnUI(attachListener)(maybeSharedValue, key); } } export function unbindSharedValues< TConfig, THandlerData, TExtendedHandlerData extends THandlerData, >( config: BaseGestureConfig<TConfig, THandlerData, TExtendedHandlerData>, handlerTag: number ) { if (Reanimated === undefined) { return; } const baseListenerId = handlerTag + SHARED_VALUE_OFFSET; for (const [key, maybeSharedValue] of Object.entries(config)) { if (!Reanimated.isSharedValue(maybeSharedValue)) { continue; } const keyHash = hash(key); const listenerId = baseListenerId + keyHash; Reanimated.runOnUI(() => { maybeSharedValue.removeListener(listenerId); })(); } } export function hasWorkletEventHandlers< TConfig, THandlerData, TExtendedHandlerData extends THandlerData, >(config: BaseGestureConfig<TConfig, THandlerData, TExtendedHandlerData>) { for (const key of HandlerCallbacks) { const value = config[key]; if (typeof value === 'function' && '__workletHash' in value) { return true; } } return false; } export function maybeUnpackValue<T>( v: SharedValueOrT<T, boolean> | undefined ): T { 'worklet'; return (Reanimated?.isSharedValue(v) ? v.value : v) as T; }