react-native-gesture-handler
Version:
Declarative API exposing native platform touch and gesture system to React Native
99 lines (95 loc) • 5.03 kB
JavaScript
;
import { useCallback, useRef, useState } from 'react';
import { isTestEnv, tagMessage } from '../../../utils';
import { flingGestureHandlerProps } from '../../FlingGestureHandler';
import { forceTouchGestureHandlerProps } from '../../ForceTouchGestureHandler';
import { baseGestureHandlerWithDetectorProps } from '../../gestureHandlerCommon';
import { longPressGestureHandlerProps } from '../../LongPressGestureHandler';
import { nativeViewGestureHandlerProps } from '../../NativeViewGestureHandler';
import { panGestureHandlerCustomNativeProps, panGestureHandlerProps } from '../../PanGestureHandler';
import { tapGestureHandlerProps } from '../../TapGestureHandler';
import { onGestureHandlerEvent } from '../eventReceiver';
import { BaseGesture } from '../gesture';
import { hoverGestureHandlerProps } from '../hoverGesture';
import { Reanimated } from '../reanimatedWrapper';
export const ALLOWED_PROPS = [...baseGestureHandlerWithDetectorProps, ...tapGestureHandlerProps, ...panGestureHandlerProps, ...panGestureHandlerCustomNativeProps, ...longPressGestureHandlerProps, ...forceTouchGestureHandlerProps, ...flingGestureHandlerProps, ...hoverGestureHandlerProps, ...nativeViewGestureHandlerProps];
// In some environments (e.g. `Next.js`) Reanimated Babel plugin might not be used.
// In that case we would wrongly suggest to add `runOnJS` to gesture configuration, even if the user doesn't use worklets at all.
// To prevent this, we check whether the plugin is enabled by defining a worklet and checking if the `__workletHash` property is available.
function emptyWorklet() {
'worklet';
}
// @ts-expect-error if `emptyWorklet` is a worklet, `__workletHash` will be available, if not then the check will return false.
const wasBabelPluginEnabled = emptyWorklet.__workletHash !== undefined;
function convertToHandlerTag(ref) {
if (typeof ref === 'number') {
return ref;
} else if (ref instanceof BaseGesture) {
return ref.handlerTag;
} else {
// @ts-ignore in this case it should be a ref either to gesture object or
// a gesture handler component, in both cases handlerTag property exists
return ref.current?.handlerTag ?? -1;
}
}
function extractValidHandlerTags(interactionGroup) {
return Array.from(new Set(interactionGroup?.map(convertToHandlerTag)?.filter(tag => tag > 0) ?? []));
}
export function extractGestureRelations(gesture) {
gesture.config.requireToFail = extractValidHandlerTags(gesture.config.requireToFail);
gesture.config.simultaneousWith = extractValidHandlerTags(gesture.config.simultaneousWith);
gesture.config.blocksHandlers = extractValidHandlerTags(gesture.config.blocksHandlers);
return {
waitFor: gesture.config.requireToFail,
simultaneousHandlers: gesture.config.simultaneousWith,
blocksHandlers: gesture.config.blocksHandlers
};
}
export function checkGestureCallbacksForWorklets(gesture) {
if (!__DEV__) {
return;
}
// If a gesture is explicitly marked to run on the JS thread there is no need to check
// if callbacks are worklets as the user is aware they will be ran on the JS thread
if (gesture.config.runOnJS) {
return;
}
const areSomeNotWorklets = gesture.handlers.isWorklet.includes(false);
const areSomeWorklets = gesture.handlers.isWorklet.includes(true);
// If some of the callbacks are worklets and some are not, and the gesture is not
// explicitly marked with `.runOnJS(true)` show an error
if (areSomeNotWorklets && areSomeWorklets) {
console.error(tagMessage(`Some of the callbacks in the gesture are worklets and some are not. Either make sure that all calbacks are marked as 'worklet' if you wish to run them on the UI thread or use '.runOnJS(true)' modifier on the gesture explicitly to run all callbacks on the JS thread.`));
}
if (Reanimated === undefined) {
// If Reanimated is not available, we can't run worklets, so we shouldn't show the warning
return;
}
const areAllNotWorklets = !areSomeWorklets && areSomeNotWorklets;
// If none of the callbacks are worklets and the gesture is not explicitly marked with
// `.runOnJS(true)` show a warning
if (areAllNotWorklets && wasBabelPluginEnabled && !isTestEnv()) {
console.warn(tagMessage(`None of the callbacks in the gesture are worklets. If you wish to run them on the JS thread use '.runOnJS(true)' modifier on the gesture to make this explicit. Otherwise, mark the callbacks as 'worklet' to run them on the UI thread.`));
}
}
export function useForceRender() {
const [renderState, setRenderState] = useState(false);
const forceRender = useCallback(() => {
setRenderState(!renderState);
}, [renderState, setRenderState]);
return forceRender;
}
export function useWebEventHandlers() {
return useRef({
onGestureHandlerEvent: e => {
onGestureHandlerEvent(e.nativeEvent);
},
onGestureHandlerStateChange: e => {
onGestureHandlerEvent(e.nativeEvent);
},
onGestureHandlerTouchEvent: () => {
// no-op
}
});
}
//# sourceMappingURL=utils.js.map