Skip to content

⬅️ Back to Table of Contents

📄 usePointerSwipe

📊 Analysis Summary

Metric Count
🔧 Functions 5
📦 Imports 15
🟢 Vue Composition API 6
📐 Interfaces 2

📚 Table of Contents

🛠️ File Location:

📂 packages/core/usePointerSwipe/index.ts

📦 Imports

Name Source
ComputedRef vue
DeepReadonly vue
MaybeRefOrGetter vue
ShallowRef vue
PointerType ../types
Position ../types
UseSwipeDirection ../useSwipe
toRef @vueuse/shared
tryOnMounted @vueuse/shared
computed vue
deepReadonly vue
reactive vue
shallowReadonly vue
shallowRef vue
useEventListener ../useEventListener

Vue Composition API

Name Type Reactive Variables Composables
reactive reactive none none
reactive reactive none none
computed computed none none
computed computed none none
computed computed none none
computed computed none none

Functions

usePointerSwipe(target: MaybeRefOrGetter<HTMLElement | null | u…, options: UsePointerSwipeOptions): UsePointerSwipeReturn

Reactive swipe detection based on PointerEvents.

Parameters:

  • target any: No description
  • options any: No description

See: https://vueuse.org/usePointerSwipe

Raw JSDoc
/**
 * Reactive swipe detection based on PointerEvents.
 *
 * @see https://vueuse.org/usePointerSwipe
 * @param target
 * @param options
 */

Calls:

  • toRef (from @vueuse/shared)
  • reactive (from vue)
  • computed (from vue)
  • max
  • abs
  • shallowRef (from vue)
  • options.pointerTypes?.includes
  • useEventListener (from ../useEventListener)
  • eventIsAllowed
  • eventTarget?.setPointerCapture
  • updatePosStart
  • updatePosEnd
  • onSwipeStart
  • onSwipe
  • onSwipeEnd
  • tryOnMounted (from @vueuse/shared)
  • targetRef.value?.style?.setProperty
  • stops.forEach
  • s
  • shallowReadonly (from vue)
  • deepReadonly (from vue)

Internal Comments:

// Future pointer events will be retargeted to target until pointerup/cancel (x2)
// Allow vertical scrolling, disable horizontal scrolling by touch (x6)
// Disable text selection on swipe (x6)

Code
export function usePointerSwipe(
  target: MaybeRefOrGetter<HTMLElement | null | undefined>,
  options: UsePointerSwipeOptions = {},
): UsePointerSwipeReturn {
  const targetRef = toRef(target)

  const {
    threshold = 50,
    onSwipe,
    onSwipeEnd,
    onSwipeStart,
    disableTextSelect = false,
  } = options

  const posStart = reactive<Position>({ x: 0, y: 0 })
  const updatePosStart = (x: number, y: number) => {
    posStart.x = x
    posStart.y = y
  }

  const posEnd = reactive<Position>({ x: 0, y: 0 })
  const updatePosEnd = (x: number, y: number) => {
    posEnd.x = x
    posEnd.y = y
  }

  const distanceX = computed(() => posStart.x - posEnd.x)
  const distanceY = computed(() => posStart.y - posEnd.y)

  const { max, abs } = Math
  const isThresholdExceeded = computed(() => max(abs(distanceX.value), abs(distanceY.value)) >= threshold)
  const isSwiping = shallowRef(false)
  const isPointerDown = shallowRef(false)

  const direction = computed(() => {
    if (!isThresholdExceeded.value)
      return 'none'

    if (abs(distanceX.value) > abs(distanceY.value)) {
      return distanceX.value > 0
        ? 'left'
        : 'right'
    }
    else {
      return distanceY.value > 0
        ? 'up'
        : 'down'
    }
  })

  const eventIsAllowed = (e: PointerEvent): boolean => {
    const isReleasingButton = e.buttons === 0
    const isPrimaryButton = e.buttons === 1
    return options.pointerTypes?.includes(e.pointerType as PointerType) ?? (isReleasingButton || isPrimaryButton) ?? true
  }

  const listenerOptions = { passive: true }

  const stops = [
    useEventListener(target, 'pointerdown', (e: PointerEvent) => {
      if (!eventIsAllowed(e))
        return
      isPointerDown.value = true
      // Future pointer events will be retargeted to target until pointerup/cancel
      const eventTarget = e.target as HTMLElement | undefined
      eventTarget?.setPointerCapture(e.pointerId)
      const { clientX: x, clientY: y } = e
      updatePosStart(x, y)
      updatePosEnd(x, y)
      onSwipeStart?.(e)
    }, listenerOptions),

    useEventListener(target, 'pointermove', (e: PointerEvent) => {
      if (!eventIsAllowed(e))
        return
      if (!isPointerDown.value)
        return

      const { clientX: x, clientY: y } = e
      updatePosEnd(x, y)
      if (!isSwiping.value && isThresholdExceeded.value)
        isSwiping.value = true
      if (isSwiping.value)
        onSwipe?.(e)
    }, listenerOptions),

    useEventListener(target, ['pointerup', 'pointercancel'], (e: PointerEvent) => {
      if (!eventIsAllowed(e))
        return
      if (isSwiping.value)
        onSwipeEnd?.(e, direction.value)

      isPointerDown.value = false
      isSwiping.value = false
    }, listenerOptions),
  ]

  tryOnMounted(() => {
    // Allow vertical scrolling, disable horizontal scrolling by touch
    targetRef.value?.style?.setProperty('touch-action', 'pan-y')

    if (disableTextSelect) {
    // Disable text selection on swipe
      targetRef.value?.style?.setProperty('-webkit-user-select', 'none')
      targetRef.value?.style?.setProperty('-ms-user-select', 'none')
      targetRef.value?.style?.setProperty('user-select', 'none')
    }
  })

  const stop = () => stops.forEach(s => s())

  return {
    isSwiping: shallowReadonly(isSwiping),
    direction: shallowReadonly(direction),
    posStart: deepReadonly(posStart),
    posEnd: deepReadonly(posEnd),
    distanceX,
    distanceY,
    stop,
  }
}

Internal helpers

Declared inside another function in this file.

updatePosStart(x: number, y: number): void

Parameters:

  • x number
  • y number

Returns: void

Code
(x: number, y: number) => {
    posStart.x = x
    posStart.y = y
  }

updatePosEnd(x: number, y: number): void

Parameters:

  • x number
  • y number

Returns: void

Code
(x: number, y: number) => {
    posEnd.x = x
    posEnd.y = y
  }

eventIsAllowed(e: PointerEvent): boolean

Parameters:

  • e PointerEvent

Returns: boolean

Calls:

  • options.pointerTypes?.includes
Code
(e: PointerEvent): boolean => {
    const isReleasingButton = e.buttons === 0
    const isPrimaryButton = e.buttons === 1
    return options.pointerTypes?.includes(e.pointerType as PointerType) ?? (isReleasingButton || isPrimaryButton) ?? true
  }

stop(): void

Returns: void

Calls:

  • stops.forEach
Code
() => stops.forEach(s => s())

Interfaces

UsePointerSwipeOptions

Interface Code
export interface UsePointerSwipeOptions {
  /**
   * @default 50
   */
  threshold?: number

  /**
   * Callback on swipe start.
   */
  onSwipeStart?: (e: PointerEvent) => void

  /**
   * Callback on swipe move.
   */
  onSwipe?: (e: PointerEvent) => void

  /**
   * Callback on swipe end.
   */
  onSwipeEnd?: (e: PointerEvent, direction: UseSwipeDirection) => void

  /**
   * Pointer types to listen to.
   *
   * @default ['mouse', 'touch', 'pen']
   */
  pointerTypes?: PointerType[]

  /**
   * Disable text selection on swipe.
   *
   * @default false
   */
  disableTextSelect?: boolean
}

Properties

Name Type Optional Description
threshold number not shown
onSwipeStart (e: PointerEvent) => void not shown
onSwipe (e: PointerEvent) => void not shown
onSwipeEnd (e: PointerEvent, direction: UseSwipeDirection) => void not shown
pointerTypes PointerType[] not shown
disableTextSelect boolean not shown

UsePointerSwipeReturn

Interface Code
export interface UsePointerSwipeReturn {
  readonly isSwiping: ShallowRef<boolean>
  direction: Readonly<ShallowRef<UseSwipeDirection>>
  readonly posStart: DeepReadonly<Position>
  readonly posEnd: DeepReadonly<Position>
  distanceX: Readonly<ComputedRef<number>>
  distanceY: Readonly<ComputedRef<number>>
  stop: () => void
}

Properties

Name Type Optional Description
isSwiping ShallowRef<boolean> not shown
direction Readonly<ShallowRef<UseSwipeDirection>> not shown
posStart DeepReadonly<Position> not shown
posEnd DeepReadonly<Position> not shown
distanceX Readonly<ComputedRef<number>> not shown
distanceY Readonly<ComputedRef<number>> not shown
stop () => void not shown

Generated by Syntax Scribe