UNPKG

react-native-gesture-handler

Version:

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

164 lines (140 loc) 4.15 kB
import type { GestureEvent, HandlerData, WithSharedValue, } from '../../../types'; import { SingleGestureName } from '../../../types'; import { useGesture } from '../../useGesture'; import { getChangeEventCalculator, maybeUnpackValue, useClonedAndRemappedConfig, } from '../../utils'; import type { OffsetProps, PanExtendedHandlerData, PanGesture, PanGestureConfig, PanGestureInternalConfig, PanGestureInternalProperties, PanGestureProperties, PanHandlerData, } from './PanTypes'; const PanPropsMapping = new Map< keyof PanGestureProperties, keyof PanGestureInternalProperties >([ ['minDistance', 'minDist'], ['averageTouches', 'avgTouches'], ]); function validateOffsetsArray( offsets: WithSharedValue<number | [number, number] | undefined>, propName: string ) { if (offsets === undefined) { return; } if (!Array.isArray(offsets)) { return; } const offsetStart = maybeUnpackValue<number>(offsets[0]); const offsetEnd = maybeUnpackValue<number>(offsets[1]); if (offsetStart > 0 || offsetEnd < 0) { throw new Error( `First element of ${propName} should be negative, and the second one should be positive` ); } } function validatePanConfig(config: PanGestureConfig) { validateOffsetsArray(config.activeOffsetX, 'activeOffsetX'); validateOffsetsArray(config.activeOffsetY, 'activeOffsetY'); validateOffsetsArray(config.failOffsetX, 'failOffsetX'); validateOffsetsArray(config.failOffsetY, 'failOffsetY'); if ( config.minDistance !== undefined && (config.failOffsetX !== undefined || config.failOffsetY !== undefined) ) { throw new Error( `It is not supported to use minDistance with failOffsetX or failOffsetY, use activeOffsetX and activeOffsetY instead` ); } if ( config.minDistance !== undefined && (config.activeOffsetX !== undefined || config.activeOffsetY !== undefined) ) { throw new Error( `It is not supported to use minDistance with activeOffsetX or activeOffsetY` ); } } function transformOffsetProp( config: PanGestureConfig & PanGestureInternalConfig, propName: keyof OffsetProps ) { const propValue = config[propName]; if (propValue === undefined) { return; } if (Array.isArray(propValue)) { config[`${propName}Start`] = propValue[0]; config[`${propName}End`] = propValue[1]; } else { const offsetValue = maybeUnpackValue<number>(propValue); if (offsetValue < 0) { config[`${propName}Start`] = propValue; } else { config[`${propName}End`] = propValue; } } // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete config[propName]; } function diffCalculator( current: HandlerData<PanExtendedHandlerData>, previous: HandlerData<PanExtendedHandlerData> | null ) { 'worklet'; return { changeX: previous ? current.translationX - previous.translationX : current.translationX, changeY: previous ? current.translationY - previous.translationY : current.translationY, }; } function fillInDefaultValues(event: GestureEvent<PanExtendedHandlerData>) { 'worklet'; event.changeX = 0; event.changeY = 0; } function transformPanProps( config: PanGestureConfig & PanGestureInternalConfig ) { transformOffsetProp(config, 'activeOffsetY'); transformOffsetProp(config, 'failOffsetX'); transformOffsetProp(config, 'failOffsetY'); transformOffsetProp(config, 'activeOffsetX'); config.changeEventCalculator = getChangeEventCalculator(diffCalculator); config.fillInDefaultValues = fillInDefaultValues; return config; } const EMPTY_PAN_CONFIG: PanGestureConfig = {}; export function usePanGesture( config: PanGestureConfig = EMPTY_PAN_CONFIG ): PanGesture { if (__DEV__) { validatePanConfig(config); } const panConfig = useClonedAndRemappedConfig< PanGestureProperties, PanHandlerData, PanGestureInternalProperties, PanExtendedHandlerData >(config, PanPropsMapping, transformPanProps); return useGesture< PanGestureInternalProperties, PanHandlerData, PanExtendedHandlerData >(SingleGestureName.Pan, panConfig); }