forked from vitest-dev/vitest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
121 lines (110 loc) · 3.1 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { Ref, ref, unref, computed } from 'vue-demi'
import { MaybeRef, toRefs, isClient } from '@vueuse/shared'
import { useEventListener } from '../useEventListener'
import { PointerType, Position } from '../types'
import { defaultWindow } from '../_configurable'
export interface UseDraggableOptions {
/**
* Only start the dragging when click on the element directly
*
* @default false
*/
exact?: MaybeRef<boolean>
/**
* Prevent events defaults
*
* @default false
*/
preventDefault?: MaybeRef<boolean>
/**
* Element to attach `pointermove` and `pointerup` events to.
*
* @default window
*/
draggingElement?: MaybeRef<HTMLElement | SVGElement | Window | Document | null>
/**
* Pointer types that listen to.
*
* @default ['mouse', 'touch', 'pen']
*/
pointerTypes?: PointerType[]
/**
* Initial position of the element.
*
* @default { x: 0, y: 0}
*/
initialValue?: MaybeRef<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
}
/**
* Make elements draggable.
*
* @see https://vueuse.org/useDraggable
* @param target
* @param options
*/
export function useDraggable(target: MaybeRef<HTMLElement | SVGElement | null>, options: UseDraggableOptions = {}) {
const draggingElement = options.draggingElement ?? defaultWindow
const position: Ref<Position> = ref(options.initialValue ?? { x: 0, y: 0 })
const pressedDelta = ref<Position>()
const filterEvent = (e: PointerEvent) => {
if (options.pointerTypes)
return options.pointerTypes.includes(e.pointerType as PointerType)
return true
}
const preventDefault = (e: PointerEvent) => {
if (unref(options.preventDefault))
e.preventDefault()
}
const start = (e: PointerEvent) => {
if (!filterEvent(e))
return
if (unref(options.exact) && e.target !== unref(target))
return
const react = unref(target)!.getBoundingClientRect()
const pos = {
x: e.pageX - react.left,
y: e.pageY - react.top,
}
if (options.onStart?.(pos, e) === false)
return
pressedDelta.value = pos
preventDefault(e)
}
const move = (e: PointerEvent) => {
if (!filterEvent(e))
return
if (!pressedDelta.value)
return
position.value = {
x: e.pageX - pressedDelta.value.x,
y: e.pageY - pressedDelta.value.y,
}
options.onMove?.(position.value, e)
preventDefault(e)
}
const end = (e: PointerEvent) => {
if (!filterEvent(e))
return
pressedDelta.value = undefined
preventDefault(e)
}
if (isClient) {
useEventListener(target, 'pointerdown', start, true)
useEventListener(draggingElement, 'pointermove', move, true)
useEventListener(draggingElement, 'pointerup', end, true)
}
return {
...toRefs(position),
position,
isDragging: computed(() => !!pressedDelta.value),
style: computed(() => `left:${position.value.x}px;top:${position.value.y}px;`),
}
}