Skip to content

Commit

Permalink
feat(useMousePressed): new function
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Dec 4, 2020
1 parent e8290b6 commit 2deeb6a
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 4 deletions.
46 changes: 46 additions & 0 deletions packages/core/useMousePressed/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# useMousePressed

> Reactive mouse pressing state. Triggered by `mousedown` `touchstart` on target element and released by `mouseup` `mouseleave` `touchend` `touchcancel` on window.
## Basic Usage

```js
import { useMousePressed } from '@vueuse/core'

const { pressed } = useMousePressed()
```

Touching is enabled by default. To make it only detects mouse changes, set `touch` to `false`

```js
const { pressed } = useMousePressed({ touch: false })
```

To only capture `mousedown` and `touchstart` on specific element, you can specify `target` by passing a ref of the element.


```html {16-20}
<template>
<div ref="el">
Only clicking on this element will trigger the update.
</div>
</template>

<script>
import { ref } from 'vue'
import { useMousePressed } from '@vueuse/core'
export default {
setup() {
const el = ref(null)
const { pressed } = useMousePressed({ target: el })
return {
el,
pressed,
}
}
})
</script>
```
39 changes: 39 additions & 0 deletions packages/core/useMousePressed/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { defineComponent, ref, computed } from 'vue-demi'
import { useMousePressed } from '.'
import { defineDemo, html } from '../../_docs'
import { useToggle } from '@vueuse/shared/useToggle'

defineDemo(
{
name: 'useMousePressed',
category: 'Sensors',
docs: require('./index.md'),
module,
},
defineComponent({
setup() {
const el = ref(null)
const [withTarget, toggle] = useToggle()
const target = computed(() => {
if (withTarget.value)
return el.value
return window
})
return {
el,
withTarget,
toggle,
...useMousePressed({ target }),
}
},

template: html`
<div ref='el' class="select-none">
<pre>Pressed: {{ pressed }}</pre>
<pre>Source Type: {{ JSON.stringify(sourceType) }}</pre>
<br>
<span @click='toggle' class="mt-4 underline cursor-pointer">{{ withTarget ? 'Tracking on this Demo section' : 'Tracking on Window' }}</span>
</div>
`,
}),
)
97 changes: 97 additions & 0 deletions packages/core/useMousePressed/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { Fn, MaybeRef } from '@vueuse/shared'
import { ref, watch } from 'vue-demi'
import { useEventListener } from '../useEventListener'
import { MouseSourceType } from '../useMouse'
import { ConfigurableWindow, defaultWindow } from '../_configurable'

export interface MousePressedOptions extends ConfigurableWindow {
/**
* Listen to `touchstart` `touchend` events
*
* @default true
*/
touch?: boolean

/**
* Initial values
*
* @default false
*/
initialValue?: boolean

/**
* Element target to be capture the click
*/
target?: MaybeRef<Element | null |undefined>
}

/**
* Reactive mouse position.
*
* @see {@link https://vueuse.js.org/useMousePressed}
* @param options
*/
export function useMousePressed(options: MousePressedOptions = {}) {
const {
touch = true,
initialValue = false,
window = defaultWindow,
} = options

const target = ref(options.target)
const pressed = ref(initialValue)
const sourceType = ref<MouseSourceType>(null)

let listeners: Fn[] = []

if (window) {
const cleanup = () => {
listeners.forEach(f => f())
listeners = []
}
const onReleased = () => {
pressed.value = false
sourceType.value = null
}

watch(
target,
() => {
cleanup()

const t = target.value || window
listeners.push(useEventListener(t, 'mousedown',
() => {
pressed.value = true
sourceType.value = 'mouse'
},
{ passive: true },
))

if (touch) {
listeners.push(useEventListener(t, 'touchstart',
() => {
pressed.value = true
sourceType.value = 'touch'
},
{ passive: true },
))
}
},
{ immediate: true },
)

useEventListener(window, 'mouseleave', onReleased, { passive: true })
useEventListener(window, 'mouseup', onReleased, { passive: true })

if (touch) {
useEventListener(window, 'touchend', onReleased, { passive: true })
useEventListener(window, 'touchcancel', onReleased, { passive: true })
}
}

return {
pressed,
sourceType,
}
}
8 changes: 4 additions & 4 deletions packages/shared/useToggle/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { ref } from 'vue-demi'

/**
* A boolean switcher with utility functions.
* A boolean ref with a toggler
*
* @see {@link https://vueuse.js.org/useToggle}
* @param [initialValue=false]
*/
export function useToggle(initialValue = false) {
const value = ref(initialValue)
const toggle = () => (value.value = !value.value)
const boolean = ref(initialValue)
const toggle = () => (boolean.value = !boolean.value)

return [value, toggle]
return [boolean, toggle] as const
}

0 comments on commit 2deeb6a

Please sign in to comment.