import React, { useEffect } from 'react'; import { GestureDetectorType, InterceptingGestureDetector } from './detectors'; import { NativeDetector } from './detectors/NativeDetector'; import { VirtualDetector } from './detectors/VirtualDetector/VirtualDetector'; import { useNativeGesture } from './hooks/gestures'; import { NativeWrapperProps } from './hooks/utils'; import type { NativeWrapperProperties, WrapperSpecificProperties, } from './types/NativeWrapperType'; export default function createNativeWrapper( Component: React.ComponentType, config: Readonly< Omit, keyof WrapperSpecificProperties> > = {}, detectorType: GestureDetectorType = GestureDetectorType.Native ) { const ComponentWrapper = ( props: TProps & NativeWrapperProperties ) => { const { ref, onGestureUpdate_CAN_CAUSE_INFINITE_RERENDER, ...restProps } = props; // Filter out props that should be passed to gesture handler wrapper const { gestureHandlerProps, childProps } = Object.keys(restProps).reduce( (res, key) => { // @ts-ignore TS being overly protective with it's types, see https://github.com/microsoft/TypeScript/issues/26255#issuecomment-458013731 for more info if (NativeWrapperProps.has(key)) { // @ts-ignore FIXME(TS) res.gestureHandlerProps[key] = props[key]; } else { // @ts-ignore FIXME(TS) res.childProps[key] = props[key]; } return res; }, { gestureHandlerProps: { ...config }, // Watch out not to modify config childProps: { enabled: props.enabled, hitSlop: props.hitSlop, testID: props.testID, } as TProps, } ); if (gestureHandlerProps.disableReanimated === undefined) { gestureHandlerProps.disableReanimated = true; } const native = useNativeGesture(gestureHandlerProps); useEffect(() => { onGestureUpdate_CAN_CAUSE_INFINITE_RERENDER?.(native); }, [native, onGestureUpdate_CAN_CAUSE_INFINITE_RERENDER]); const DetectorComponent = detectorType === GestureDetectorType.Intercepting ? InterceptingGestureDetector : detectorType === GestureDetectorType.Virtual ? VirtualDetector : NativeDetector; return ( ); }; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment ComponentWrapper.displayName = Component?.displayName || // @ts-ignore if render doesn't exist it will return undefined and go further Component?.render?.name || (typeof Component === 'string' && Component) || 'ComponentWrapper'; return ComponentWrapper; }