"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.DraggableTrigger = void 0;
var _reactNativeGestureHandler = require("react-native-gesture-handler");
var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
var _element = require("@wordpress/element");
var _style = _interopRequireDefault(require("./style.scss"));
var _jsxRuntime = require("react/jsx-runtime");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
 * External dependencies
 */

/**
 * WordPress dependencies
 */

/**
 * Internal dependencies
 */

const Context = (0, _element.createContext)({});
const {
  Provider
} = Context;

/**
 * Draggable component.
 *
 * @param {Object}      props               Component props.
 * @param {JSX.Element} props.children      Children to be rendered.
 * @param {Function}    [props.onDragEnd]   Callback when dragging ends.
 * @param {Function}    [props.onDragOver]  Callback when dragging happens over an element.
 * @param {Function}    [props.onDragStart] Callback when dragging starts.
 * @param {string}      [props.testID]      Id used for querying the pan gesture in tests.
 *
 * @return {JSX.Element} The component to be rendered.
 */
const Draggable = ({
  children,
  onDragEnd,
  onDragOver,
  onDragStart,
  testID
}) => {
  const isDragging = (0, _reactNativeReanimated.useSharedValue)(false);
  const isPanActive = (0, _reactNativeReanimated.useSharedValue)(false);
  const draggingId = (0, _reactNativeReanimated.useSharedValue)('');
  const panGestureRef = (0, _element.useRef)();
  const currentFirstTouchId = (0, _reactNativeReanimated.useSharedValue)(null);
  const initialPosition = {
    x: (0, _reactNativeReanimated.useSharedValue)(0),
    y: (0, _reactNativeReanimated.useSharedValue)(0)
  };
  const lastPosition = {
    x: (0, _reactNativeReanimated.useSharedValue)(0),
    y: (0, _reactNativeReanimated.useSharedValue)(0)
  };
  (0, _reactNativeReanimated.useAnimatedReaction)(() => isDragging.value, (result, previous) => {
    if (result === previous) {
      return;
    }
    if (result) {
      if (onDragStart) {
        onDragStart({
          x: initialPosition.x.value,
          y: initialPosition.y.value,
          id: draggingId.value
        });
      }
    } else if (previous !== null && onDragEnd) {
      onDragEnd({
        x: lastPosition.x.value,
        y: lastPosition.y.value,
        id: draggingId.value
      });
    }
  });
  function getFirstTouchEvent(event) {
    'worklet';

    return event.allTouches.find(touch => touch.id === currentFirstTouchId.value);
  }
  const panGesture = _reactNativeGestureHandler.Gesture.Pan().manualActivation(true).onTouchesDown(event => {
    if (!currentFirstTouchId.value) {
      const firstEvent = event.allTouches[0];
      const {
        x = 0,
        y = 0
      } = firstEvent;
      currentFirstTouchId.value = firstEvent.id;
      initialPosition.x.value = x;
      initialPosition.y.value = y;
    }
  }).onTouchesMove((event, state) => {
    if (!isPanActive.value && isDragging.value) {
      isPanActive.value = true;
      state.activate();
    }
    if (isPanActive.value && isDragging.value) {
      const firstEvent = getFirstTouchEvent(event);
      if (!firstEvent) {
        state.end();
        return;
      }
      lastPosition.x.value = firstEvent.x;
      lastPosition.y.value = firstEvent.y;
      if (onDragOver) {
        onDragOver(firstEvent);
      }
    }
  }).onTouchesCancelled((_event, state) => {
    state.end();
  }).onEnd(() => {
    currentFirstTouchId.value = null;
    isPanActive.value = false;
    isDragging.value = false;
  }).withRef(panGestureRef).shouldCancelWhenOutside(false).withTestId(testID);
  const providerValue = (0, _element.useMemo)(() => {
    return {
      panGestureRef,
      isDragging,
      isPanActive,
      draggingId
    };
  }, [
  // `isDragging`, `isPanActive` and `draggingId` are created using the
  // `useSharedValue` hook provided by the `react-native-reanimated`, which in
  // theory should guarantee that the value of these variables remains stable.
  // ESLint can't pick this up, and that's why they have to be specified as
  // dependencies for this hook call.
  isDragging, isPanActive, draggingId]);
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, {
    gesture: panGesture,
    children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
      style: _style.default.draggable__container,
      children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Provider, {
        value: providerValue,
        children: children
      })
    })
  });
};

/**
 * Draggable trigger component.
 *
 * This component acts as the trigger for the dragging functionality.
 *
 * @param {Object}      props                  Component props.
 * @param {JSX.Element} props.children         Children to be rendered.
 * @param {*}           props.id               Identifier passed within the event callbacks.
 * @param {boolean}     [props.enabled]        Enables the long-press gesture.
 * @param {number}      [props.maxDistance]    Maximum distance, that defines how far the finger is allowed to travel during a long press gesture.
 * @param {number}      [props.minDuration]    Minimum time, that a finger must remain pressed on the corresponding view.
 * @param {Function}    [props.onLongPress]    Callback when long-press gesture is triggered over an element.
 * @param {Function}    [props.onLongPressEnd] Callback when long-press gesture ends.
 * @param {string}      [props.testID]         Id used for querying the long-press gesture handler in tests.
 *
 * @return {JSX.Element} The component to be rendered.
 */
const DraggableTrigger = ({
  children,
  enabled = true,
  id,
  maxDistance = 1000,
  minDuration = 500,
  onLongPress,
  onLongPressEnd,
  testID
}) => {
  const {
    panGestureRef,
    isDragging,
    isPanActive,
    draggingId
  } = (0, _element.useContext)(Context);
  const gestureHandler = (0, _reactNativeReanimated.useAnimatedGestureHandler)({
    onActive: () => {
      if (isDragging.value) {
        return;
      }
      draggingId.value = id;
      isDragging.value = true;
      if (onLongPress) {
        (0, _reactNativeReanimated.runOnJS)(onLongPress)(id);
      }
    },
    onEnd: () => {
      if (!isPanActive.value) {
        isDragging.value = false;
      }
      if (onLongPressEnd) {
        (0, _reactNativeReanimated.runOnJS)(onLongPressEnd)(id);
      }
    }
  });
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.LongPressGestureHandler, {
    enabled: enabled,
    minDurationMs: minDuration,
    maxDist: maxDistance,
    simultaneousHandlers: panGestureRef,
    shouldCancelWhenOutside: false,
    onGestureEvent: gestureHandler,
    testID: testID,
    children: children
  });
};
exports.DraggableTrigger = DraggableTrigger;
var _default = exports.default = Draggable;
//# sourceMappingURL=index.native.js.map