@tamagui/react-native-web-lite
Version:
React Native for Web
164 lines (163 loc) • 8.56 kB
JavaScript
import { InteractionManager } from "@tamagui/react-native-web-internals";
import TouchHistoryMath from "../vendor/react-native/TouchHistoryMath/index.native.js";
var {
currentCentroidX,
currentCentroidY,
currentCentroidXOfTouchesChangedAfter,
currentCentroidYOfTouchesChangedAfter,
previousCentroidXOfTouchesChangedAfter,
previousCentroidYOfTouchesChangedAfter
} = TouchHistoryMath,
PanResponder = {
_initializeGestureState(gestureState) {
gestureState.x = 0, gestureState.y = 0, gestureState.initialX = 0, gestureState.initialY = 0, gestureState.deltaX = 0, gestureState.deltaY = 0, gestureState.velocityX = 0, gestureState.velocityY = 0, gestureState.numberActiveTouches = 0, gestureState._accountsForMovesUpTo = 0;
},
/**
* Take all recently moved touches, calculate how the centroid has changed just for those
* recently moved touches, and append that change to an accumulator. This is
* to (at least) handle the case where the user is moving three fingers, and
* then one of the fingers stops but the other two continue.
*
* This is very different than taking all of the recently moved touches and
* storing their centroid as `dx/dy`. For correctness, we must *accumulate
* changes* in the centroid of recently moved touches.
*
* There is also some nuance with how we handle multiple moved touches in a
* single event. Multiple touches generate two 'move' events, each of
* them triggering `onResponderMove`. But with the way `PanResponder` works,
* all of the gesture inference is performed on the first dispatch, since it
* looks at all of the touches. Therefore, `PanResponder` does not call
* `onResponderMove` passed the first dispatch. This diverges from the
* typical responder callback pattern (without using `PanResponder`), but
* avoids more dispatches than necessary.
*
* When moving two touches in opposite directions, the cumulative
* distance is zero in each dimension. When two touches move in parallel five
* pixels in the same direction, the cumulative distance is five, not ten. If
* two touches start, one moves five in a direction, then stops and the other
* touch moves fives in the same direction, the cumulative distance is ten.
*
* This logic requires a kind of processing of time "clusters" of touch events
* so that two touch moves that essentially occur in parallel but move every
* other frame respectively, are considered part of the same movement.
*
* x/y: If a move event has been observed, `(x, y)` is the centroid of the most
* recently moved "cluster" of active touches.
* deltaX/deltaY: Cumulative touch distance. Accounts for touch moves that are
* clustered together in time, moving the same direction. Only valid when
* currently responder (otherwise, it only represents the drag distance below
* the threshold).
*/
_updateGestureStateOnMove(gestureState, touchHistory) {
var movedAfter = gestureState._accountsForMovesUpTo,
prevX = previousCentroidXOfTouchesChangedAfter(touchHistory, movedAfter),
prevY = previousCentroidYOfTouchesChangedAfter(touchHistory, movedAfter),
prevDeltaX = gestureState.deltaX,
prevDeltaY = gestureState.deltaY,
x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter),
y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter),
deltaX = prevDeltaX + (x - prevX),
deltaY = prevDeltaY + (y - prevY),
dt = touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
gestureState.deltaX = deltaX, gestureState.deltaY = deltaY, gestureState.numberActiveTouches = touchHistory.numberActiveTouches, gestureState.velocityX = (deltaX - prevDeltaX) / dt, gestureState.velocityY = (deltaY - prevDeltaY) / dt, gestureState.x = x, gestureState.y = y, gestureState._accountsForMovesUpTo = touchHistory.mostRecentTimeStamp;
},
/**
* Enhanced versions of all of the responder callbacks that provide not only
* the `ResponderEvent`, but also the `PanResponder` gesture state.
*
* In general, for events that have capture equivalents, we update the
* gestureState once in the capture phase and can use it in the bubble phase
* as well.
*/
create(config) {
var interactionState = {
handle: null
},
gestureState = {
// Useful for debugging
stateID: Math.random(),
x: 0,
y: 0,
initialX: 0,
initialY: 0,
deltaX: 0,
deltaY: 0,
velocityX: 0,
velocityY: 0,
numberActiveTouches: 0,
_accountsForMovesUpTo: 0
},
{
onStartShouldSetResponder,
onStartShouldSetResponderCapture,
onMoveShouldSetResponder,
onMoveShouldSetResponderCapture,
onPanGrant,
onPanStart,
onPanMove,
onPanEnd,
onPanRelease,
onPanReject,
onPanTerminate,
onPanTerminationRequest
} = config,
panHandlers = {
onStartShouldSetResponder(event) {
return onStartShouldSetResponder != null ? onStartShouldSetResponder(event, gestureState) : !1;
},
onMoveShouldSetResponder(event) {
return onMoveShouldSetResponder != null ? onMoveShouldSetResponder(event, gestureState) : !1;
},
onStartShouldSetResponderCapture(event) {
return event.nativeEvent.touches.length === 1 && PanResponder._initializeGestureState(gestureState), gestureState.numberActiveTouches = event.touchHistory.numberActiveTouches, onStartShouldSetResponderCapture != null ? onStartShouldSetResponderCapture(event, gestureState) : !1;
},
onMoveShouldSetResponderCapture(event) {
var touchHistory = event.touchHistory;
return PanResponder._updateGestureStateOnMove(gestureState, touchHistory), onMoveShouldSetResponderCapture != null ? onMoveShouldSetResponderCapture(event, gestureState) : !1;
},
onResponderGrant(event) {
interactionState.handle || (interactionState.handle = InteractionManager.createInteractionHandle()), gestureState.initialX = currentCentroidX(event.touchHistory), gestureState.initialY = currentCentroidY(event.touchHistory), gestureState.deltaX = 0, gestureState.deltaY = 0, onPanGrant?.(event, gestureState);
},
onResponderReject(event) {
clearInteractionHandle(interactionState, onPanReject, event, gestureState);
},
onResponderStart(event) {
var {
numberActiveTouches
} = event.touchHistory;
gestureState.numberActiveTouches = numberActiveTouches, onPanStart?.(event, gestureState);
},
onResponderMove(event) {
var touchHistory = event.touchHistory;
gestureState._accountsForMovesUpTo !== touchHistory.mostRecentTimeStamp && (PanResponder._updateGestureStateOnMove(gestureState, touchHistory), onPanMove?.(event, gestureState));
},
onResponderEnd(event) {
var {
numberActiveTouches
} = event.touchHistory;
gestureState.numberActiveTouches = numberActiveTouches, clearInteractionHandle(interactionState, onPanEnd, event, gestureState);
},
onResponderRelease(event) {
clearInteractionHandle(interactionState, onPanRelease, event, gestureState), PanResponder._initializeGestureState(gestureState);
},
onResponderTerminate(event) {
clearInteractionHandle(interactionState, onPanTerminate, event, gestureState), PanResponder._initializeGestureState(gestureState);
},
onResponderTerminationRequest(event) {
return onPanTerminationRequest != null ? onPanTerminationRequest(event, gestureState) : !0;
}
};
return {
panHandlers,
getInteractionHandle() {
return interactionState.handle;
}
};
}
};
function clearInteractionHandle(interactionState, callback, event, gestureState) {
interactionState.handle && (InteractionManager.clearInteractionHandle(interactionState.handle), interactionState.handle = null), callback && callback(event, gestureState);
}
var Alternative_default = PanResponder;
export { Alternative_default as default };
//# sourceMappingURL=Alternative.js.map