react-native-gesture-handler
Version:
Declarative API exposing native platform touch and gesture system to React Native
107 lines (101 loc) • 3.21 kB
JavaScript
;
import { Reanimated, Worklets } from '../../../handlers/gestures/reanimatedWrapper';
import { normalizeHitSlop } from '../../../handlers/hitSlop';
import { NativeProxy } from '../../NativeProxy';
import { HandlerCallbacks } from './propsWhiteList';
import { isComposedGesture } from './relationUtils';
// Variant of djb2 hash function.
// Taken from https://gist.github.com/eplawless/52813b1d8ad9af510d85?permalink_comment_id=3367765#gistcomment-3367765
function hash(str) {
'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(config, handlerTag) {
const scheduleOnUI = Worklets?.scheduleOnUI;
if (Reanimated === undefined || scheduleOnUI === undefined) {
return;
}
const baseListenerId = handlerTag + SHARED_VALUE_OFFSET;
const {
shouldUseReanimatedDetector
} = config;
const attachListener = (sharedValue, configKey) => {
'worklet';
const keyHash = hash(configKey);
const listenerId = baseListenerId + keyHash;
sharedValue.addListener(listenerId, value => {
if (configKey === 'runOnJS') {
updateGestureHandlerConfig(handlerTag, {
dispatchesReanimatedEvents: shouldUseReanimatedDetector && !value
});
return;
}
if (configKey === 'hitSlop') {
updateGestureHandlerConfig(handlerTag, {
hitSlop: normalizeHitSlop(value)
});
return;
}
updateGestureHandlerConfig(handlerTag, {
[configKey]: value
});
});
};
for (const [key, maybeSharedValue] of Object.entries(config)) {
if (!Reanimated.isSharedValue(maybeSharedValue)) {
continue;
}
scheduleOnUI(attachListener, maybeSharedValue, key);
}
}
export function unbindSharedValues(config, handlerTag) {
const scheduleOnUI = Worklets?.scheduleOnUI;
if (Reanimated === undefined || scheduleOnUI === 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;
scheduleOnUI(() => {
maybeSharedValue.removeListener(listenerId);
});
}
}
export function hasWorkletEventHandlers(config) {
for (const key of HandlerCallbacks) {
const value = config[key];
if (typeof value === 'function' && '__workletHash' in value) {
return true;
}
}
return false;
}
export function maybeUnpackValue(v) {
'worklet';
return Reanimated?.isSharedValue(v) ? v.value : v;
}
export function getEnabledSharedValues(gesture) {
if (Reanimated === undefined) {
return [];
}
if (isComposedGesture(gesture)) {
return gesture.gestures.flatMap(getEnabledSharedValues);
}
const enabled = gesture.config.enabled;
return Reanimated.isSharedValue(enabled) ? [enabled] : [];
}
//# sourceMappingURL=reanimatedUtils.js.map