react-native-screen-transitions
Version: 
Easy screen transitions for React Native and Expo
219 lines (210 loc) • 6.85 kB
JavaScript
"use strict";
import { DEFAULT_ACTIVATION_AREA, DEFAULT_EDGE_DISTANCE_HORIZONTAL, DEFAULT_EDGE_DISTANCE_VERTICAL, GESTURE_ACTIVATION_THRESHOLD_X, GESTURE_ACTIVATION_THRESHOLD_Y, GESTURE_FAIL_TOLERANCE_X, GESTURE_FAIL_TOLERANCE_Y } from "../../constants";
import { GestureOffsetState } from "../../types/gesture";
function normalizeSides(area) {
  "worklet";
  if (!area || typeof area === "string") {
    const mode = area ?? DEFAULT_ACTIVATION_AREA;
    return {
      left: mode,
      right: mode,
      top: mode,
      bottom: mode
    };
  }
  const s = area;
  return {
    left: s.left ?? DEFAULT_ACTIVATION_AREA,
    right: s.right ?? DEFAULT_ACTIVATION_AREA,
    top: s.top ?? DEFAULT_ACTIVATION_AREA,
    bottom: s.bottom ?? DEFAULT_ACTIVATION_AREA
  };
}
function computeEdgeConstraints(initialTouch, dimensions, sides, responseDistance) {
  "worklet";
  const xDist = responseDistance ?? DEFAULT_EDGE_DISTANCE_HORIZONTAL;
  const yDist = responseDistance ?? DEFAULT_EDGE_DISTANCE_VERTICAL;
  const horizontalRight = sides.left === "screen" || initialTouch.x <= xDist; // right swipe checks left edge
  const horizontalLeft = sides.right === "screen" || initialTouch.x >= dimensions.width - xDist; // left swipe checks right edge
  const verticalDown = sides.top === "screen" || initialTouch.y <= yDist; // down swipe checks top edge
  const verticalUp = sides.bottom === "screen" || initialTouch.y >= dimensions.height - yDist; // up swipe checks bottom edge
  return {
    horizontalRight,
    horizontalLeft,
    verticalDown,
    verticalUp
  };
}
function calculateSwipeDirs(deltaX, deltaY) {
  "worklet";
  const isVerticalSwipe = Math.abs(deltaY) > Math.abs(deltaX);
  const isHorizontalSwipe = Math.abs(deltaX) > Math.abs(deltaY);
  const isSwipingDown = isVerticalSwipe && deltaY > 0;
  const isSwipingUp = isVerticalSwipe && deltaY < 0;
  const isSwipingRight = isHorizontalSwipe && deltaX > 0;
  const isSwipingLeft = isHorizontalSwipe && deltaX < 0;
  return {
    isSwipingDown,
    isSwipingUp,
    isSwipingRight,
    isSwipingLeft,
    isVerticalSwipe,
    isHorizontalSwipe
  };
}
function shouldActivateOrFail(params) {
  "worklet";
  const {
    deltaX,
    deltaY,
    hasHorizontal,
    hasVertical,
    isHorizontalSwipe,
    isVerticalSwipe,
    allowedRight,
    allowedLeft,
    allowedUp,
    allowedDown,
    horizontalGateRight,
    horizontalGateLeft,
    verticalGateUp,
    verticalGateDown,
    isSwipingRight,
    isSwipingLeft,
    isSwipingUp,
    isSwipingDown
  } = params;
  let shouldActivate = false;
  let shouldFail = false;
  if (hasHorizontal && isHorizontalSwipe) {
    const hasEnoughHorizontalMovement = Math.abs(deltaX) >= GESTURE_ACTIVATION_THRESHOLD_X;
    const hasAcceptableVerticalDeviation = Math.abs(deltaY) <= GESTURE_FAIL_TOLERANCE_X;
    if (hasEnoughHorizontalMovement && hasAcceptableVerticalDeviation) {
      const rightOk = isSwipingRight && allowedRight && horizontalGateRight;
      const leftOk = isSwipingLeft && allowedLeft && horizontalGateLeft;
      if (rightOk || leftOk) {
        shouldActivate = true;
      }
    } else if (!hasAcceptableVerticalDeviation) {
      shouldFail = true;
    }
  }
  if (hasVertical && isVerticalSwipe) {
    const hasEnoughVerticalMovement = Math.abs(deltaY) >= GESTURE_ACTIVATION_THRESHOLD_Y;
    const hasAcceptableHorizontalDeviation = Math.abs(deltaX) <= GESTURE_FAIL_TOLERANCE_Y;
    if (hasEnoughVerticalMovement && hasAcceptableHorizontalDeviation) {
      const upOk = isSwipingUp && allowedUp && verticalGateUp;
      const downOk = isSwipingDown && allowedDown && verticalGateDown;
      if (upOk || downOk) {
        shouldActivate = true;
      }
    } else if (!hasAcceptableHorizontalDeviation) {
      shouldFail = true;
    }
  }
  if (hasHorizontal && isHorizontalSwipe) {
    if (isSwipingLeft && !allowedLeft || isSwipingRight && !allowedRight) {
      shouldFail = true;
    }
    // If gating prohibits the dominant horizontal swipe, fail early
    if (isSwipingRight && allowedRight && !horizontalGateRight || isSwipingLeft && allowedLeft && !horizontalGateLeft) {
      shouldFail = true;
    }
  }
  if (hasVertical && isVerticalSwipe) {
    if (isSwipingUp && !allowedUp || isSwipingDown && !allowedDown) {
      shouldFail = true;
    }
    // If gating prohibits the dominant vertical swipe, fail early
    if (isSwipingUp && allowedUp && !verticalGateUp || isSwipingDown && allowedDown && !verticalGateDown) {
      shouldFail = true;
    }
  }
  return {
    shouldActivate,
    shouldFail
  };
}
/**
 * Since we're using onTouchesMove to activate our pan, faillOffset and activateOffset don't actually work. In that case we'll create this function to use in onTouchesMove which acts simarly to the original functionality.
 */
export const applyOffsetRules = ({
  initialTouch,
  touch,
  directions,
  manager,
  gestureOffsetState,
  activationArea,
  dimensions,
  responseDistance
}) => {
  "worklet";
  const deltaX = touch.x - initialTouch.x;
  const deltaY = touch.y - initialTouch.y;
  const allowedDown = directions.vertical;
  const allowedUp = directions.verticalInverted;
  const allowedRight = directions.horizontal;
  const allowedLeft = directions.horizontalInverted;
  const hasHorizontal = allowedLeft || allowedRight;
  const hasVertical = allowedUp || allowedDown;
  const {
    isSwipingDown,
    isSwipingUp,
    isSwipingRight,
    isSwipingLeft,
    isVerticalSwipe,
    isHorizontalSwipe
  } = calculateSwipeDirs(deltaX, deltaY);
  // avoid re-running the function if the activation state is already set
  if (gestureOffsetState.value === GestureOffsetState.PASSED || gestureOffsetState.value === GestureOffsetState.FAILED) {
    return {
      isSwipingDown,
      isSwipingUp,
      isSwipingRight,
      isSwipingLeft
    };
  }
  const sides = normalizeSides(activationArea);
  const {
    horizontalRight: horizontalGateRight,
    horizontalLeft: horizontalGateLeft,
    verticalDown: verticalGateDown,
    verticalUp: verticalGateUp
  } = computeEdgeConstraints(initialTouch, dimensions, sides, responseDistance);
  const {
    shouldActivate,
    shouldFail
  } = shouldActivateOrFail({
    deltaX,
    deltaY,
    hasHorizontal,
    hasVertical,
    isHorizontalSwipe,
    isVerticalSwipe,
    allowedRight,
    allowedLeft,
    allowedUp,
    allowedDown,
    horizontalGateRight,
    horizontalGateLeft,
    verticalGateUp,
    verticalGateDown,
    isSwipingRight,
    isSwipingLeft,
    isSwipingUp,
    isSwipingDown
  });
  if (shouldActivate) {
    gestureOffsetState.value = GestureOffsetState.PASSED;
  } else if (shouldFail) {
    gestureOffsetState.value = GestureOffsetState.FAILED;
    manager?.fail();
  }
  return {
    isSwipingDown,
    isSwipingUp,
    isSwipingRight,
    isSwipingLeft
  };
};
//# sourceMappingURL=apply-offset-rules.js.map