import { addPointerEvent as k } from "../../events/add-pointer-event.es.js";
import { extractEventInfo as B } from "../../events/event-info.es.js";
import { getContextWindow as j } from "../../utils/get-context-window.es.js";
import { isRefObject as P } from "../../utils/is-ref-object.es.js";
import { PanSession as T } from "../pan/PanSession.es.js";
import { applyConstraints as b, calcRelativeConstraints as I, resolveDragElastic as w, calcViewportConstraints as R, defaultElastic as O, rebaseAxisConstraints as W, calcOrigin as z } from "./utils/constraints.es.js";
import { createBox as F } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/projection/geometry/models.es.js";
import { frame as C } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/frameloop/frame.es.js";
import { eachAxis as p } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/projection/utils/each-axis.es.js";
import { invariant as U } from "../../../../../../../motion-utils@12.36.0/node_modules/motion-utils/dist/es/errors.es.js";
import { measurePageBox as _ } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/projection/utils/measure.es.js";
import { convertBoxToBoundingBox as K, convertBoundingBoxToBox as N } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/projection/geometry/conversion.es.js";
import { addValueToWillChange as L } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/value/will-change/add-will-change.es.js";
import { animateMotionValue as $ } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/animation/interfaces/motion-value.es.js";
import { addDomEvent as q } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/events/add-dom-event.es.js";
import { setDragLock as G } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/gestures/drag/state/set-active.es.js";
import { percent as H } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/value/types/numbers/units.es.js";
import { calcLength as J } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/projection/geometry/delta-calc.es.js";
import { mixNumber as V } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/utils/mix/number.es.js";
import { resize as M } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/resize/index.es.js";
import { isElementTextInput as Q } from "../../../../../../../motion-dom@12.38.0/node_modules/motion-dom/dist/es/gestures/press/utils/is-keyboard-accessible.es.js";
const X = /* @__PURE__ */ new WeakMap();
class At {
  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 = F(), this.latestPointerEvent = null, this.latestPanInfo = null, this.visualElement = t;
  }
  start(t, { snapToCursor: n = !1, distanceThreshold: s } = {}) {
    const { presenceContext: i } = this.visualElement;
    if (i && i.isPresent === !1)
      return;
    const o = (r) => {
      n && this.snapToCursor(B(r).point), this.stopAnimation();
    }, e = (r, l) => {
      const { drag: g, dragPropagation: d, onDragStart: v } = this.getProps();
      if (g && !d && (this.openDragLock && this.openDragLock(), this.openDragLock = G(g), !this.openDragLock))
        return;
      this.latestPointerEvent = r, 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), p((f) => {
        let D = this.getAxisMotionValue(f).get() || 0;
        if (H.test(D)) {
          const { projection: y } = this.visualElement;
          if (y && y.layout) {
            const x = y.layout.layoutBox[f];
            x && (D = J(x) * (parseFloat(D) / 100));
          }
        }
        this.originPoint[f] = D;
      }), v && C.update(() => v(r, l), !1, !0), L(this.visualElement, "transform");
      const { animationState: E } = this.visualElement;
      E && E.setActive("whileDrag", !0);
    }, a = (r, l) => {
      this.latestPointerEvent = r, this.latestPanInfo = l;
      const { dragPropagation: g, dragDirectionLock: d, onDirectionLock: v, onDrag: E } = this.getProps();
      if (!g && !this.openDragLock)
        return;
      const { offset: f } = l;
      if (d && this.currentDirection === null) {
        this.currentDirection = Z(f), this.currentDirection !== null && v && v(this.currentDirection);
        return;
      }
      this.updateAxis("x", l.point, f), this.updateAxis("y", l.point, f), this.visualElement.render(), E && C.update(() => E(r, l), !1, !0);
    }, u = (r, l) => {
      this.latestPointerEvent = r, this.latestPanInfo = l, this.stop(r, l), this.latestPointerEvent = null, this.latestPanInfo = null;
    }, c = () => {
      const { dragSnapToOrigin: r } = this.getProps();
      (r || this.constraints) && this.startAnimation({ x: 0, y: 0 });
    }, { dragSnapToOrigin: h } = this.getProps();
    this.panSession = new T(t, {
      onSessionStart: o,
      onStart: e,
      onMove: a,
      onSessionEnd: u,
      resumeAnimation: c
    }, {
      transformPagePoint: this.visualElement.getTransformPagePoint(),
      dragSnapToOrigin: h,
      distanceThreshold: s,
      contextWindow: j(this.visualElement),
      element: this.visualElement.current
    });
  }
  /**
   * @internal
   */
  stop(t, n) {
    const s = t || this.latestPointerEvent, i = n || this.latestPanInfo, o = this.isDragging;
    if (this.cancel(), !o || !i || !s)
      return;
    const { velocity: e } = i;
    this.startAnimation(e);
    const { onDragEnd: a } = this.getProps();
    a && C.postRender(() => a(s, i));
  }
  /**
   * @internal
   */
  cancel() {
    this.isDragging = !1;
    const { projection: t, animationState: n } = this.visualElement;
    t && (t.isAnimationBlocked = !1), this.endPanSession();
    const { dragPropagation: s } = this.getProps();
    !s && this.openDragLock && (this.openDragLock(), this.openDragLock = null), n && n.setActive("whileDrag", !1);
  }
  /**
   * Clean up the pan session without modifying other drag state.
   * This is used during unmount to ensure event listeners are removed
   * without affecting projection animations or drag locks.
   * @internal
   */
  endPanSession() {
    this.panSession && this.panSession.end(), this.panSession = void 0;
  }
  updateAxis(t, n, s) {
    const { drag: i } = this.getProps();
    if (!s || !A(t, i, this.currentDirection))
      return;
    const o = this.getAxisMotionValue(t);
    let e = this.originPoint[t] + s[t];
    this.constraints && this.constraints[t] && (e = b(e, this.constraints[t], this.elastic[t])), o.set(e);
  }
  resolveConstraints() {
    var o;
    const { dragConstraints: t, dragElastic: n } = this.getProps(), s = this.visualElement.projection && !this.visualElement.projection.layout ? this.visualElement.projection.measure(!1) : (o = this.visualElement.projection) == null ? void 0 : o.layout, i = this.constraints;
    t && P(t) ? this.constraints || (this.constraints = this.resolveRefConstraints()) : t && s ? this.constraints = I(s.layoutBox, t) : this.constraints = !1, this.elastic = w(n), i !== this.constraints && !P(t) && s && this.constraints && !this.hasMutatedConstraints && p((e) => {
      this.constraints !== !1 && this.getAxisMotionValue(e) && (this.constraints[e] = W(s.layoutBox[e], this.constraints[e]));
    });
  }
  resolveRefConstraints() {
    const { dragConstraints: t, onMeasureDragConstraints: n } = this.getProps();
    if (!t || !P(t))
      return !1;
    const s = t.current;
    U(s !== 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 o = _(s, i.root, this.visualElement.getTransformPagePoint());
    let e = R(i.layout.layoutBox, o);
    if (n) {
      const a = n(K(e));
      this.hasMutatedConstraints = !!a, a && (e = N(a));
    }
    return e;
  }
  startAnimation(t) {
    const { drag: n, dragMomentum: s, dragElastic: i, dragTransition: o, dragSnapToOrigin: e, onDragTransitionEnd: a } = this.getProps(), u = this.constraints || {}, c = p((h) => {
      if (!A(h, n, this.currentDirection))
        return;
      let r = u && u[h] || {};
      (e === !0 || e === h) && (r = { min: 0, max: 0 });
      const l = i ? 200 : 1e6, g = i ? 40 : 1e7, d = {
        type: "inertia",
        velocity: s ? t[h] : 0,
        bounceStiffness: l,
        bounceDamping: g,
        timeConstant: 750,
        restDelta: 1,
        restSpeed: 10,
        ...o,
        ...r
      };
      return this.startAxisValueAnimation(h, d);
    });
    return Promise.all(c).then(a);
  }
  startAxisValueAnimation(t, n) {
    const s = this.getAxisMotionValue(t);
    return L(this.visualElement, t), s.start($(t, s, 0, n, this.visualElement, !1));
  }
  stopAnimation() {
    p((t) => this.getAxisMotionValue(t).stop());
  }
  /**
   * 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 n = `_drag${t.toUpperCase()}`, s = this.visualElement.getProps(), i = s[n];
    return i || this.visualElement.getValue(t, (s.initial ? s.initial[t] : void 0) || 0);
  }
  snapToCursor(t) {
    p((n) => {
      const { drag: s } = this.getProps();
      if (!A(n, s, this.currentDirection))
        return;
      const { projection: i } = this.visualElement, o = this.getAxisMotionValue(n);
      if (i && i.layout) {
        const { min: e, max: a } = i.layout.layoutBox[n], u = o.get() || 0;
        o.set(t[n] - V(e, a, 0.5) + u);
      }
    });
  }
  /**
   * 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: n } = this.getProps(), { projection: s } = this.visualElement;
    if (!P(n) || !s || !this.constraints)
      return;
    this.stopAnimation();
    const i = { x: 0, y: 0 };
    p((e) => {
      const a = this.getAxisMotionValue(e);
      if (a && this.constraints !== !1) {
        const u = a.get();
        i[e] = z({ min: u, max: u }, this.constraints[e]);
      }
    });
    const { transformTemplate: o } = this.visualElement.getProps();
    this.visualElement.current.style.transform = o ? o({}, "") : "none", s.root && s.root.updateScroll(), s.updateLayout(), this.constraints = !1, this.resolveConstraints(), p((e) => {
      if (!A(e, t, null))
        return;
      const a = this.getAxisMotionValue(e), { min: u, max: c } = this.constraints[e];
      a.set(V(u, c, i[e]));
    }), this.visualElement.render();
  }
  addListeners() {
    if (!this.visualElement.current)
      return;
    X.set(this.visualElement, this);
    const t = this.visualElement.current, n = k(t, "pointerdown", (c) => {
      const { drag: h, dragListener: r = !0 } = this.getProps(), l = c.target, g = l !== t && Q(l);
      h && r && !g && this.start(c);
    });
    let s;
    const i = () => {
      const { dragConstraints: c } = this.getProps();
      P(c) && c.current && (this.constraints = this.resolveRefConstraints(), s || (s = Y(t, c.current, () => this.scalePositionWithinConstraints())));
    }, { projection: o } = this.visualElement, e = o.addEventListener("measure", i);
    o && !o.layout && (o.root && o.root.updateScroll(), o.updateLayout()), C.read(i);
    const a = q(window, "resize", () => this.scalePositionWithinConstraints()), u = o.addEventListener("didUpdate", ({ delta: c, hasLayoutChanged: h }) => {
      this.isDragging && h && (p((r) => {
        const l = this.getAxisMotionValue(r);
        l && (this.originPoint[r] += c[r].translate, l.set(l.get() + c[r].translate));
      }), this.visualElement.render());
    });
    return () => {
      a(), n(), e(), u && u(), s && s();
    };
  }
  getProps() {
    const t = this.visualElement.getProps(), { drag: n = !1, dragDirectionLock: s = !1, dragPropagation: i = !1, dragConstraints: o = !1, dragElastic: e = O, dragMomentum: a = !0 } = t;
    return {
      ...t,
      drag: n,
      dragDirectionLock: s,
      dragPropagation: i,
      dragConstraints: o,
      dragElastic: e,
      dragMomentum: a
    };
  }
}
function S(m) {
  let t = !0;
  return () => {
    if (t) {
      t = !1;
      return;
    }
    m();
  };
}
function Y(m, t, n) {
  const s = M(m, S(n)), i = M(t, S(n));
  return () => {
    s(), i();
  };
}
function A(m, t, n) {
  return (t === !0 || t === m) && (n === null || n === m);
}
function Z(m, t = 10) {
  let n = null;
  return Math.abs(m.y) > t ? n = "y" : Math.abs(m.x) > t && (n = "x"), n;
}
export {
  At as VisualElementDragControls,
  X as elementDragControls
};
//# sourceMappingURL=VisualElementDragControls.es.js.map
