Skip to content

Commit 7792566

Browse files
Merge pull request #404 from PrefectHQ/nicholas/feature-use-mouse-position-2024-03-15
Feature: `useMousePosition`
2 parents f46425f + ba12737 commit 7792566

File tree

5 files changed

+95
-0
lines changed

5 files changed

+95
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ npm i --save @prefecthq/vue-compositions
2222
- [useIsSame](https://github.com/prefecthq/vue-compositions/tree/main/src/useIsSame)
2323
- [useKeyDown](https://github.com/prefecthq/vue-compositions/tree/main/src/useKeyDown)
2424
- [useMedia](https://github.com/prefecthq/vue-compositions/tree/main/src/useMedia)
25+
- [useMousePosition](https://github.com/prefecthq/vue-compositions/tree/main/src/useMousePosition)
2526
- [useMutationObserver](https://github.com/prefecthq/vue-compositions/tree/main/src/useMutationObserver)
2627
- [useNow](https://github.com/prefecthq/vue-compositions/tree/main/src/useNow)
2728
- [usePatchRef](https://github.com/prefecthq/vue-compositions/tree/main/src/usePatchRef)

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export * from './useIntersectionObserver'
1010
export * from './useIsSame'
1111
export * from './useKeyDown'
1212
export * from './useMedia'
13+
export * from './useMousePosition'
1314
export * from './useMutationObserver'
1415
export * from './useNow'
1516
export * from './usePatchRef'

src/useMousePosition/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# useMedia
2+
The `useMousePosition` composition is a utility composition that passively tracks the position of the mouse as well as the position of the mouse at last click
3+
4+
## Example
5+
```typescript
6+
import { useMousePosition } from '@prefecthq/vue-compositions'
7+
8+
const { position, positionAtLastClick } = useMousePosition()
9+
```
10+
11+
## Arguments
12+
None
13+
14+
## Returns
15+
```ts
16+
type MousePosition {
17+
x: number,
18+
y: number
19+
}
20+
21+
type UseMousePosition {
22+
position: MousePosition,
23+
positionAtLastClick: MousePosition
24+
}
25+
```

src/useMousePosition/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './useMousePosition'
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { onScopeDispose, reactive, ref } from 'vue'
2+
import { useGlobalEventListener } from '@/useGlobalEventListener'
3+
4+
export type MousePosition = {
5+
x: number,
6+
y: number,
7+
}
8+
9+
export type UseMousePosition = {
10+
position: MousePosition,
11+
positionAtLastClick: MousePosition,
12+
}
13+
14+
const position = reactive<MousePosition>({ x: 0, y: 0 })
15+
const positionAtLastClick = reactive<MousePosition>({ x: 0, y: 0 })
16+
17+
const updatePositionAtLastClick = (): void => {
18+
Object.assign(positionAtLastClick, position)
19+
}
20+
21+
const updateMousePosition = (event: MouseEvent): void => {
22+
position.x = event.clientX
23+
position.y = event.clientY
24+
25+
if (positionAtLastClick.x === 0 && positionAtLastClick.y === 0) {
26+
updatePositionAtLastClick()
27+
}
28+
}
29+
30+
const listeners = ref(0)
31+
32+
const { add: addMouseMoveEventListener, remove: removeMouseMoveEventListener } = useGlobalEventListener('mousemove', updateMousePosition, { passive: true })
33+
const { add: addClickEventListener, remove: removeClickEventListener } = useGlobalEventListener('click', updatePositionAtLastClick, { capture: true })
34+
const { add: addContextMenuEventListener, remove: removeContextMenuEventListener } = useGlobalEventListener('contextmenu', updatePositionAtLastClick, { capture: true })
35+
36+
function tryTeardownEventListeners(): void {
37+
if (listeners.value > 0) {
38+
return
39+
}
40+
41+
removeMouseMoveEventListener()
42+
removeClickEventListener()
43+
removeContextMenuEventListener()
44+
}
45+
46+
function addEventListeners(): void {
47+
// These have no effect if the event listeners are already added
48+
addMouseMoveEventListener()
49+
addClickEventListener()
50+
addContextMenuEventListener()
51+
}
52+
53+
export function useMousePosition(): UseMousePosition {
54+
listeners.value += 1
55+
56+
addEventListeners()
57+
58+
onScopeDispose(() => {
59+
listeners.value -= 1
60+
tryTeardownEventListeners()
61+
})
62+
63+
return {
64+
position,
65+
positionAtLastClick,
66+
}
67+
}

0 commit comments

Comments
 (0)