import { animateMotionValue as M } from "../../animation/interfaces/motion-value.es.js";
import { addDomEvent as S } from "../../events/add-dom-event.es.js";
import { addPointerEvent as B } from "../../events/add-pointer-event.es.js";
import { extractEventInfo as k } from "../../events/event-info.es.js";
import { convertBoxToBoundingBox as j, convertBoundingBoxToBox as T } from "../../projection/geometry/conversion.es.js";
import { calcLength as w } from "../../projection/geometry/delta-calc.es.js";
import { createBox as b } from "../../projection/geometry/models.es.js";
import { eachAxis as h } from "../../projection/utils/each-axis.es.js";
import { measurePageBox as I } from "../../projection/utils/measure.es.js";
import { getContextWindow as R } from "../../utils/get-context-window.es.js";
import { isRefObject as D } from "../../utils/is-ref-object.es.js";
import { addValueToWillChange as x } from "../../value/use-will-change/add-will-change.es.js";
import { PanSession as W } from "../pan/PanSession.es.js";
import { applyConstraints as O, calcRelativeConstraints as U, resolveDragElastic as z, calcViewportConstraints as _, defaultElastic as F, rebaseAxisConstraints as K, calcOrigin as N } from "./utils/constraints.es.js";
import { frame as y } from "../../../../../../../motion-dom@12.23.23/node_modules/motion-dom/dist/es/frameloop/frame.es.js";
import { invariant as $ } from "../../../../../../../motion-utils@12.23.6/node_modules/motion-utils/dist/es/errors.es.js";
import { setDragLock as q } from "../../../../../../../motion-dom@12.23.23/node_modules/motion-dom/dist/es/gestures/drag/state/set-active.es.js";
import { percent as G } from "../../../../../../../motion-dom@12.23.23/node_modules/motion-dom/dist/es/value/types/numbers/units.es.js";
import { mixNumber as L } from "../../../../../../../motion-dom@12.23.23/node_modules/motion-dom/dist/es/utils/mix/number.es.js";
const H = /* @__PURE__ */ new WeakMap();
class dt {
  constructor(t) {
    this.openDragLock = null, this.isDragging = !1, this.currentDirection = null, this.originPoint = { x: 0, y: 0 }, this.constraints = !1, this.hasMutatedConstraints = !1, this.elastic = b(), this.latestPointerEvent = null, this.latestPanInfo = null, this.visualElement = t;
  }
  start(t, { snapToCursor: s = !1, distanceThreshold: n } = {}) {
    const { presenceContext: i } = this.visualElement;
    if (i && i.isPresent === !1)
      return;
    const r = (a) => {
      const { dragSnapToOrigin: l } = this.getProps();
      l ? this.pauseAnimation() : this.stopAnimation(), s && this.snapToCursor(k(a).point);
    }, e = (a, l) => {
      const { drag: f, dragPropagation: d, onDragStart: v } = this.getProps();
      if (f && !d && (this.openDragLock && this.openDragLock(), this.openDragLock = q(f), !this.openDragLock))
        return;
      this.latestPointerEvent = a, this.latestPanInfo = l, this.isDragging = !0, this.currentDirection = null, this.resolveConstraints(), this.visualElement.projection && (this.visualElement.projection.isAnimationBlocked = !0, this.visualElement.projection.target = void 0), h((m) => {
        let P = this.getAxisMotionValue(m).get() || 0;
        if (G.test(P)) {
          const { projection: C } = this.visualElement;
          if (C && C.layout) {
            const V = C.layout.layoutBox[m];
            V && (P = w(V) * (parseFloat(P) / 100));
          }
        }
        this.originPoint[m] = P;
      }), v && y.postRender(() => v(a, l)), x(this.visualElement, "transform");
      const { animationState: E } = this.visualElement;
      E && E.setActive("whileDrag", !0);
    }, o = (a, l) => {
      this.latestPointerEvent = a, this.latestPanInfo = l;
      const { dragPropagation: f, dragDirectionLock: d, onDirectionLock: v, onDrag: E } = this.getProps();
      if (!f && !this.openDragLock)
        return;
      const { offset: m } = l;
      if (d && this.currentDirection === null) {
        this.currentDirection = J(m), this.currentDirection !== null && v && v(this.currentDirection);
        return;
      }
      this.updateAxis("x", l.point, m), this.updateAxis("y", l.point, m), this.visualElement.render(), E && E(a, l);
    }, c = (a, l) => {
      this.latestPointerEvent = a, this.latestPanInfo = l, this.stop(a, l), this.latestPointerEvent = null, this.latestPanInfo = null;
    }, g = () => h((a) => {
      var l;
      return this.getAnimationState(a) === "paused" && ((l = this.getAxisMotionValue(a).animation) == null ? void 0 : l.play());
    }), { dragSnapToOrigin: u } = this.getProps();
    this.panSession = new W(t, {
      onSessionStart: r,
      onStart: e,
      onMove: o,
      onSessionEnd: c,
      resumeAnimation: g
    }, {
      transformPagePoint: this.visualElement.getTransformPagePoint(),
      dragSnapToOrigin: u,
      distanceThreshold: n,
      contextWindow: R(this.visualElement)
    });
  }
  /**
   * @internal
   */
  stop(t, s) {
    const n = t || this.latestPointerEvent, i = s || this.latestPanInfo, r = this.isDragging;
    if (this.cancel(), !r || !i || !n)
      return;
    const { velocity: e } = i;
    this.startAnimation(e);
    const { onDragEnd: o } = this.getProps();
    o && y.postRender(() => o(n, i));
  }
  /**
   * @internal
   */
  cancel() {
    this.isDragging = !1;
    const { projection: t, animationState: s } = this.visualElement;
    t && (t.isAnimationBlocked = !1), this.panSession && this.panSession.end(), this.panSession = void 0;
    const { dragPropagation: n } = this.getProps();
    !n && this.openDragLock && (this.openDragLock(), this.openDragLock = null), s && s.setActive("whileDrag", !1);
  }
  updateAxis(t, s, n) {
    const { drag: i } = this.getProps();
    if (!n || !A(t, i, this.currentDirection))
      return;
    const r = this.getAxisMotionValue(t);
    let e = this.originPoint[t] + n[t];
    this.constraints && this.constraints[t] && (e = O(e, this.constraints[t], this.elastic[t])), r.set(e);
  }
  resolveConstraints() {
    var r;
    const { dragConstraints: t, dragElastic: s } = this.getProps(), n = this.visualElement.projection && !this.visualElement.projection.layout ? this.visualElement.projection.measure(!1) : (r = this.visualElement.projection) == null ? void 0 : r.layout, i = this.constraints;
    t && D(t) ? this.constraints || (this.constraints = this.resolveRefConstraints()) : t && n ? this.constraints = U(n.layoutBox, t) : this.constraints = !1, this.elastic = z(s), i !== this.constraints && n && this.constraints && !this.hasMutatedConstraints && h((e) => {
      this.constraints !== !1 && this.getAxisMotionValue(e) && (this.constraints[e] = K(n.layoutBox[e], this.constraints[e]));
    });
  }
  resolveRefConstraints() {
    const { dragConstraints: t, onMeasureDragConstraints: s } = this.getProps();
    if (!t || !D(t))
      return !1;
    const n = t.current;
    $(n !== null, "If `dragConstraints` is set as a React ref, that ref must be passed to another component's `ref` prop.", "drag-constraints-ref");
    const { projection: i } = this.visualElement;
    if (!i || !i.layout)
      return !1;
    const r = I(n, i.root, this.visualElement.getTransformPagePoint());
    let e = _(i.layout.layoutBox, r);
    if (s) {
      const o = s(j(e));
      this.hasMutatedConstraints = !!o, o && (e = T(o));
    }
    return e;
  }
  startAnimation(t) {
    const { drag: s, dragMomentum: n, dragElastic: i, dragTransition: r, dragSnapToOrigin: e, onDragTransitionEnd: o } = this.getProps(), c = this.constraints || {}, g = h((u) => {
      if (!A(u, s, this.currentDirection))
        return;
      let a = c && c[u] || {};
      e && (a = { min: 0, max: 0 });
      const l = i ? 200 : 1e6, f = i ? 40 : 1e7, d = {
        type: "inertia",
        velocity: n ? t[u] : 0,
        bounceStiffness: l,
        bounceDamping: f,
        timeConstant: 750,
        restDelta: 1,
        restSpeed: 10,
        ...r,
        ...a
      };
      return this.startAxisValueAnimation(u, d);
    });
    return Promise.all(g).then(o);
  }
  startAxisValueAnimation(t, s) {
    const n = this.getAxisMotionValue(t);
    return x(this.visualElement, t), n.start(M(t, n, 0, s, this.visualElement, !1));
  }
  stopAnimation() {
    h((t) => this.getAxisMotionValue(t).stop());
  }
  pauseAnimation() {
    h((t) => {
      var s;
      return (s = this.getAxisMotionValue(t).animation) == null ? void 0 : s.pause();
    });
  }
  getAnimationState(t) {
    var s;
    return (s = this.getAxisMotionValue(t).animation) == null ? void 0 : s.state;
  }
  /**
   * Drag works differently depending on which props are provided.
   *
   * - If _dragX and _dragY are provided, we output the gesture delta directly to those motion values.
   * - Otherwise, we apply the delta to the x/y motion values.
   */
  getAxisMotionValue(t) {
    const s = `_drag${t.toUpperCase()}`, n = this.visualElement.getProps(), i = n[s];
    return i || this.visualElement.getValue(t, (n.initial ? n.initial[t] : void 0) || 0);
  }
  snapToCursor(t) {
    h((s) => {
      const { drag: n } = this.getProps();
      if (!A(s, n, this.currentDirection))
        return;
      const { projection: i } = this.visualElement, r = this.getAxisMotionValue(s);
      if (i && i.layout) {
        const { min: e, max: o } = i.layout.layoutBox[s];
        r.set(t[s] - L(e, o, 0.5));
      }
    });
  }
  /**
   * When the viewport resizes we want to check if the measured constraints
   * have changed and, if so, reposition the element within those new constraints
   * relative to where it was before the resize.
   */
  scalePositionWithinConstraints() {
    if (!this.visualElement.current)
      return;
    const { drag: t, dragConstraints: s } = this.getProps(), { projection: n } = this.visualElement;
    if (!D(s) || !n || !this.constraints)
      return;
    this.stopAnimation();
    const i = { x: 0, y: 0 };
    h((e) => {
      const o = this.getAxisMotionValue(e);
      if (o && this.constraints !== !1) {
        const c = o.get();
        i[e] = N({ min: c, max: c }, this.constraints[e]);
      }
    });
    const { transformTemplate: r } = this.visualElement.getProps();
    this.visualElement.current.style.transform = r ? r({}, "") : "none", n.root && n.root.updateScroll(), n.updateLayout(), this.resolveConstraints(), h((e) => {
      if (!A(e, t, null))
        return;
      const o = this.getAxisMotionValue(e), { min: c, max: g } = this.constraints[e];
      o.set(L(c, g, i[e]));
    });
  }
  addListeners() {
    if (!this.visualElement.current)
      return;
    H.set(this.visualElement, this);
    const t = this.visualElement.current, s = B(t, "pointerdown", (c) => {
      const { drag: g, dragListener: u = !0 } = this.getProps();
      g && u && this.start(c);
    }), n = () => {
      const { dragConstraints: c } = this.getProps();
      D(c) && c.current && (this.constraints = this.resolveRefConstraints());
    }, { projection: i } = this.visualElement, r = i.addEventListener("measure", n);
    i && !i.layout && (i.root && i.root.updateScroll(), i.updateLayout()), y.read(n);
    const e = S(window, "resize", () => this.scalePositionWithinConstraints()), o = i.addEventListener("didUpdate", ({ delta: c, hasLayoutChanged: g }) => {
      this.isDragging && g && (h((u) => {
        const a = this.getAxisMotionValue(u);
        a && (this.originPoint[u] += c[u].translate, a.set(a.get() + c[u].translate));
      }), this.visualElement.render());
    });
    return () => {
      e(), s(), r(), o && o();
    };
  }
  getProps() {
    const t = this.visualElement.getProps(), { drag: s = !1, dragDirectionLock: n = !1, dragPropagation: i = !1, dragConstraints: r = !1, dragElastic: e = F, dragMomentum: o = !0 } = t;
    return {
      ...t,
      drag: s,
      dragDirectionLock: n,
      dragPropagation: i,
      dragConstraints: r,
      dragElastic: e,
      dragMomentum: o
    };
  }
}
function A(p, t, s) {
  return (t === !0 || t === p) && (s === null || s === p);
}
function J(p, t = 10) {
  let s = null;
  return Math.abs(p.y) > t ? s = "y" : Math.abs(p.x) > t && (s = "x"), s;
}
export {
  dt as VisualElementDragControls,
  H as elementDragControls
};
//# sourceMappingURL=VisualElementDragControls.es.js.map
