{"version":3,"sources":["../../../../src/sensors/useOnLongPress/core.ts"],"sourcesContent":["import { observable } from \"@legendapp/state\";\nimport { type Fn, onUnmount, peek } from \"@usels/core\";\nimport type { DeepMaybeObservable } from \"@usels/core\";\nimport type { MaybeEventTarget } from \"../../types\";\nimport { createEventListener } from \"../../browser/useEventListener/core\";\n\nconst DEFAULT_DELAY = 500;\nconst DEFAULT_THRESHOLD = 10;\n\nexport interface UseOnLongPressModifiers {\n  /** Call `stopPropagation()` on pointer events */\n  stop?: boolean;\n  /** Remove listeners after the first long press cycle */\n  once?: boolean;\n  /** Call `preventDefault()` on pointer events */\n  prevent?: boolean;\n  /** Use capturing phase for event listeners */\n  capture?: boolean;\n  /** Only trigger when `event.target` is the element itself */\n  self?: boolean;\n}\n\nexport interface UseOnLongPressOptions {\n  /**\n   * Time in ms till `longpress` gets called\n   * @default 500\n   */\n  delay?: number;\n  /**\n   * Allowance of moving distance in pixels.\n   * The action will get canceled when moving too far from the pointerdown position.\n   * Set to `false` to disable distance checking.\n   * @default 10\n   */\n  distanceThreshold?: number | false;\n  /**\n   * Event modifiers\n   */\n  modifiers?: UseOnLongPressModifiers;\n  /**\n   * Function called when the element is released.\n   * @param duration - How long the element was pressed in ms\n   * @param distance - Distance from the pointerdown position\n   * @param isLongPress - Whether the action was a long press or not\n   * @param event - The native PointerEvent\n   */\n  onMouseUp?: (\n    duration: number,\n    distance: number,\n    isLongPress: boolean,\n    event: PointerEvent\n  ) => void;\n}\n\n/**\n * Framework-agnostic long press gesture detector.\n *\n * Listens for `pointerdown`/`pointermove`/`pointerup`/`pointerleave` events\n * and fires the handler callback after the configured delay when held.\n *\n * @param target - The element to detect long presses on\n * @param handler - Callback fired when a long press is detected\n * @param options - Configuration options\n * @returns A stop function that removes all event listeners and clears timers\n */\nexport function createOnLongPress(\n  target: MaybeEventTarget,\n  handler: (evt: PointerEvent) => void,\n  options?: DeepMaybeObservable<UseOnLongPressOptions>\n): Fn {\n  const opts$ = observable(options);\n\n  // Timer state — closure variables cleaned up in onUnmount\n  let timeout: ReturnType<typeof setTimeout> | undefined = undefined;\n  let posStart: { x: number; y: number } | undefined = undefined;\n  let startTimestamp: number | undefined = undefined;\n  let hasLongPressed = false;\n\n  const clear = () => {\n    if (timeout != null) {\n      clearTimeout(timeout);\n      timeout = undefined;\n    }\n    posStart = undefined;\n    startTimestamp = undefined;\n    hasLongPressed = false;\n  };\n\n  const onDown = (ev: PointerEvent) => {\n    const opts = opts$.peek();\n    const el = peek(target);\n\n    if (opts?.modifiers?.self && ev.target !== el) return;\n\n    clear();\n\n    if (opts?.modifiers?.prevent) ev.preventDefault();\n    if (opts?.modifiers?.stop) ev.stopPropagation();\n\n    posStart = { x: ev.clientX, y: ev.clientY };\n    startTimestamp = ev.timeStamp;\n\n    const delay = opts?.delay ?? DEFAULT_DELAY;\n    timeout = setTimeout(() => {\n      hasLongPressed = true;\n      handler(ev);\n    }, delay);\n  };\n\n  const onMove = (ev: PointerEvent) => {\n    const opts = opts$.peek();\n    const el = peek(target);\n\n    if (opts?.modifiers?.self && ev.target !== el) return;\n    if (!posStart || opts?.distanceThreshold === false) return;\n\n    if (opts?.modifiers?.prevent) ev.preventDefault();\n    if (opts?.modifiers?.stop) ev.stopPropagation();\n\n    const dx = ev.clientX - posStart.x;\n    const dy = ev.clientY - posStart.y;\n    const distance = Math.sqrt(dx * dx + dy * dy);\n\n    if (distance >= (opts?.distanceThreshold ?? DEFAULT_THRESHOLD)) {\n      clear();\n    }\n  };\n\n  const onRelease = (ev: PointerEvent) => {\n    const opts = opts$.peek();\n    const el = peek(target);\n    const _startTimestamp = startTimestamp;\n    const _posStart = posStart;\n    const _hasLongPressed = hasLongPressed;\n\n    clear();\n\n    if (!opts?.onMouseUp || !_posStart || _startTimestamp == null) return;\n    if (opts?.modifiers?.self && ev.target !== el) return;\n    if (opts?.modifiers?.prevent) ev.preventDefault();\n    if (opts?.modifiers?.stop) ev.stopPropagation();\n\n    const dx = ev.clientX - _posStart.x;\n    const dy = ev.clientY - _posStart.y;\n    const distance = Math.sqrt(dx * dx + dy * dy);\n    opts.onMouseUp(ev.timeStamp - _startTimestamp, distance, _hasLongPressed, ev);\n  };\n\n  // Read listener options at construction time (modifiers.capture/once are structural)\n  const raw = opts$.peek();\n  const listenerOptions: AddEventListenerOptions = {\n    capture: raw?.modifiers?.capture,\n    once: raw?.modifiers?.once,\n  };\n\n  const stopDown = createEventListener(\n    target,\n    \"pointerdown\",\n    onDown as EventListener,\n    listenerOptions\n  );\n  const stopMove = createEventListener(\n    target,\n    \"pointermove\",\n    onMove as EventListener,\n    listenerOptions\n  );\n  const stopUp = createEventListener(\n    target,\n    \"pointerup\",\n    onRelease as EventListener,\n    listenerOptions\n  );\n  const stopLeave = createEventListener(\n    target,\n    \"pointerleave\",\n    onRelease as EventListener,\n    listenerOptions\n  );\n\n  const stop: Fn = () => {\n    clear();\n    stopDown();\n    stopMove();\n    stopUp();\n    stopLeave();\n  };\n\n  onUnmount(clear);\n\n  return stop;\n}\n"],"mappings":"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","names":[]}