Skip to content

⬅️ Back to Table of Contents

📄 index.ts

📊 Analysis Summary

Metric Count
🔧 Functions 7
📦 Imports 10
📊 Variables & Constants 1
🟢 Vue Composition API 2
📐 Interfaces 1
📑 Type Aliases 1

📚 Table of Contents

🛠️ File Location:

📂 packages/core/useDraggable/index.ts

📦 Imports

Name Source
MaybeRefOrGetter vue
PointerType ../types
Position ../types
isClient @vueuse/shared
toRefs @vueuse/shared
computed vue
deepRef vue
toValue vue
defaultWindow ../_configurable
useEventListener ../useEventListener

Variables & Constants

Name Type Kind Value Exported
pos { x: number; y: number; } const `{
x: e.clientX - (container ? targetRect.left - containerRect!.left + container.scrollLeft : targetRect.left),
y: e.clientY - (container ? targetRect.top - containerRect!.top + container.scrollTop : targetRect.top),
}`

Vue Composition API

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

Functions

useDraggable(target: MaybeRefOrGetter<HTMLElement | SVGElement | null | undefined>, options: UseDraggableOptions): any

Code
export function useDraggable(
  target: MaybeRefOrGetter<HTMLElement | SVGElement | null | undefined>,
  options: UseDraggableOptions = {},
) {
  const {
    pointerTypes,
    preventDefault,
    stopPropagation,
    exact,
    onMove,
    onEnd,
    onStart,
    initialValue,
    axis = 'both',
    draggingElement = defaultWindow,
    containerElement,
    handle: draggingHandle = target,
    buttons = [0],
  } = options

  const position = deepRef<Position>(
    toValue(initialValue) ?? { x: 0, y: 0 },
  )

  const pressedDelta = deepRef<Position>()

  const filterEvent = (e: PointerEvent) => {
    if (pointerTypes)
      return pointerTypes.includes(e.pointerType as PointerType)
    return true
  }

  const handleEvent = (e: PointerEvent) => {
    if (toValue(preventDefault))
      e.preventDefault()
    if (toValue(stopPropagation))
      e.stopPropagation()
  }

  const start = (e: PointerEvent) => {
    if (!toValue(buttons).includes(e.button))
      return
    if (toValue(options.disabled) || !filterEvent(e))
      return
    if (toValue(exact) && e.target !== toValue(target))
      return

    const container = toValue(containerElement)
    const containerRect = container?.getBoundingClientRect?.()
    const targetRect = toValue(target)!.getBoundingClientRect()
    const pos = {
      x: e.clientX - (container ? targetRect.left - containerRect!.left + container.scrollLeft : targetRect.left),
      y: e.clientY - (container ? targetRect.top - containerRect!.top + container.scrollTop : targetRect.top),
    }
    if (onStart?.(pos, e) === false)
      return
    pressedDelta.value = pos
    handleEvent(e)
  }
  const move = (e: PointerEvent) => {
    if (toValue(options.disabled) || !filterEvent(e))
      return
    if (!pressedDelta.value)
      return

    const container = toValue(containerElement)
    const targetRect = toValue(target)!.getBoundingClientRect()
    let { x, y } = position.value
    if (axis === 'x' || axis === 'both') {
      x = e.clientX - pressedDelta.value.x
      if (container)
        x = Math.min(Math.max(0, x), container.scrollWidth - targetRect!.width)
    }
    if (axis === 'y' || axis === 'both') {
      y = e.clientY - pressedDelta.value.y
      if (container)
        y = Math.min(Math.max(0, y), container.scrollHeight - targetRect!.height)
    }
    position.value = {
      x,
      y,
    }
    onMove?.(position.value, e)
    handleEvent(e)
  }
  const end = (e: PointerEvent) => {
    if (toValue(options.disabled) || !filterEvent(e))
      return
    if (!pressedDelta.value)
      return
    pressedDelta.value = undefined
    onEnd?.(position.value, e)
    handleEvent(e)
  }

  if (isClient) {
    const config = () => ({
      capture: options.capture ?? true,
      passive: !toValue(preventDefault),
    })
    useEventListener(draggingHandle, 'pointerdown', start, config)
    useEventListener(draggingElement, 'pointermove', move, config)
    useEventListener(draggingElement, 'pointerup', end, config)
  }

  return {
    ...toRefs(position),
    position,
    isDragging: computed(() => !!pressedDelta.value),
    style: computed(
      () => `left:${position.value.x}px;top:${position.value.y}px;`,
    ),
  }
}
  • JSDoc:

    /**
     * Make elements draggable.
     *
     * @see https://vueuse.org/useDraggable
     * @param target
     * @param options
     */
    

  • Parameters:

  • target: MaybeRefOrGetter<HTMLElement | SVGElement | null | undefined>
  • options: UseDraggableOptions
  • Return Type: any
  • Calls:
  • deepRef (from vue)
  • toValue (from vue)
  • pointerTypes.includes
  • e.preventDefault
  • e.stopPropagation
  • toValue(buttons).includes
  • filterEvent
  • container?.getBoundingClientRect
  • toValue(target)!.getBoundingClientRect
  • onStart
  • handleEvent
  • Math.min
  • Math.max
  • onMove
  • onEnd
  • useEventListener (from ../useEventListener)
  • toRefs (from @vueuse/shared)
  • computed (from vue)

filterEvent(e: PointerEvent): boolean

Code
(e: PointerEvent) => {
    if (pointerTypes)
      return pointerTypes.includes(e.pointerType as PointerType)
    return true
  }
  • Parameters:
  • e: PointerEvent
  • Return Type: boolean
  • Calls:
  • pointerTypes.includes

handleEvent(e: PointerEvent): void

Code
(e: PointerEvent) => {
    if (toValue(preventDefault))
      e.preventDefault()
    if (toValue(stopPropagation))
      e.stopPropagation()
  }
  • Parameters:
  • e: PointerEvent
  • Return Type: void
  • Calls:
  • toValue (from vue)
  • e.preventDefault
  • e.stopPropagation

start(e: PointerEvent): void

Code
(e: PointerEvent) => {
    if (!toValue(buttons).includes(e.button))
      return
    if (toValue(options.disabled) || !filterEvent(e))
      return
    if (toValue(exact) && e.target !== toValue(target))
      return

    const container = toValue(containerElement)
    const containerRect = container?.getBoundingClientRect?.()
    const targetRect = toValue(target)!.getBoundingClientRect()
    const pos = {
      x: e.clientX - (container ? targetRect.left - containerRect!.left + container.scrollLeft : targetRect.left),
      y: e.clientY - (container ? targetRect.top - containerRect!.top + container.scrollTop : targetRect.top),
    }
    if (onStart?.(pos, e) === false)
      return
    pressedDelta.value = pos
    handleEvent(e)
  }
  • Parameters:
  • e: PointerEvent
  • Return Type: void
  • Calls:
  • toValue(buttons).includes
  • toValue (from vue)
  • filterEvent
  • container?.getBoundingClientRect
  • toValue(target)!.getBoundingClientRect
  • onStart
  • handleEvent

move(e: PointerEvent): void

Code
(e: PointerEvent) => {
    if (toValue(options.disabled) || !filterEvent(e))
      return
    if (!pressedDelta.value)
      return

    const container = toValue(containerElement)
    const targetRect = toValue(target)!.getBoundingClientRect()
    let { x, y } = position.value
    if (axis === 'x' || axis === 'both') {
      x = e.clientX - pressedDelta.value.x
      if (container)
        x = Math.min(Math.max(0, x), container.scrollWidth - targetRect!.width)
    }
    if (axis === 'y' || axis === 'both') {
      y = e.clientY - pressedDelta.value.y
      if (container)
        y = Math.min(Math.max(0, y), container.scrollHeight - targetRect!.height)
    }
    position.value = {
      x,
      y,
    }
    onMove?.(position.value, e)
    handleEvent(e)
  }
  • Parameters:
  • e: PointerEvent
  • Return Type: void
  • Calls:
  • toValue (from vue)
  • filterEvent
  • toValue(target)!.getBoundingClientRect
  • Math.min
  • Math.max
  • onMove
  • handleEvent

end(e: PointerEvent): void

Code
(e: PointerEvent) => {
    if (toValue(options.disabled) || !filterEvent(e))
      return
    if (!pressedDelta.value)
      return
    pressedDelta.value = undefined
    onEnd?.(position.value, e)
    handleEvent(e)
  }
  • Parameters:
  • e: PointerEvent
  • Return Type: void
  • Calls:
  • toValue (from vue)
  • filterEvent
  • onEnd
  • handleEvent

config(): { capture: boolean; passive: boolean; }

Code
() => ({
      capture: options.capture ?? true,
      passive: !toValue(preventDefault),
    })
  • Return Type: { capture: boolean; passive: boolean; }

Interfaces

UseDraggableOptions

Interface Code
export interface UseDraggableOptions {
  /**
   * Only start the dragging when click on the element directly
   *
   * @default false
   */
  exact?: MaybeRefOrGetter<boolean>

  /**
   * Prevent events defaults
   *
   * @default false
   */
  preventDefault?: MaybeRefOrGetter<boolean>

  /**
   * Prevent events propagation
   *
   * @default false
   */
  stopPropagation?: MaybeRefOrGetter<boolean>

  /**
   * Whether dispatch events in capturing phase
   *
   * @default true
   */
  capture?: boolean

  /**
   * Element to attach `pointermove` and `pointerup` events to.
   *
   * @default window
   */
  draggingElement?: MaybeRefOrGetter<HTMLElement | SVGElement | Window | Document | null | undefined>

  /**
   * Element for calculating bounds (If not set, it will use the event's target).
   *
   * @default undefined
   */
  containerElement?: MaybeRefOrGetter<HTMLElement | SVGElement | null | undefined>

  /**
   * Handle that triggers the drag event
   *
   * @default target
   */
  handle?: MaybeRefOrGetter<HTMLElement | SVGElement | null | undefined>

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

  /**
   * Initial position of the element.
   *
   * @default { x: 0, y: 0 }
   */
  initialValue?: MaybeRefOrGetter<Position>

  /**
   * Callback when the dragging starts. Return `false` to prevent dragging.
   */
  onStart?: (position: Position, event: PointerEvent) => void | false

  /**
   * Callback during dragging.
   */
  onMove?: (position: Position, event: PointerEvent) => void

  /**
   * Callback when dragging end.
   */
  onEnd?: (position: Position, event: PointerEvent) => void

  /**
   * Axis to drag on.
   *
   * @default 'both'
   */
  axis?: 'x' | 'y' | 'both'

  /**
   * Disabled drag and drop.
   *
   * @default false
   */
  disabled?: MaybeRefOrGetter<boolean>

  /**
   * Mouse buttons that are allowed to trigger drag events.
   *
   * - `0`: Main button, usually the left button or the un-initialized state
   * - `1`: Auxiliary button, usually the wheel button or the middle button (if present)
   * - `2`: Secondary button, usually the right button
   * - `3`: Fourth button, typically the Browser Back button
   * - `4`: Fifth button, typically the Browser Forward button
   *
   * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button#value
   * @default [0]
   */
  buttons?: MaybeRefOrGetter<number[]>
}

Properties

Name Type Optional Description
exact MaybeRefOrGetter<boolean>
preventDefault MaybeRefOrGetter<boolean>
stopPropagation MaybeRefOrGetter<boolean>
capture boolean
draggingElement MaybeRefOrGetter<HTMLElement | SVGElement | Window | Document | null | undefined>
containerElement MaybeRefOrGetter<HTMLElement | SVGElement | null | undefined>
handle MaybeRefOrGetter<HTMLElement | SVGElement | null | undefined>
pointerTypes PointerType[]
initialValue MaybeRefOrGetter<Position>
onStart (position: Position, event: PointerEvent) => void | false
onMove (position: Position, event: PointerEvent) => void
onEnd (position: Position, event: PointerEvent) => void
axis 'x' | 'y' | 'both'
disabled MaybeRefOrGetter<boolean>
buttons MaybeRefOrGetter<number[]>

Type Aliases

UseDraggableReturn

type UseDraggableReturn = ReturnType<typeof useDraggable>;