Skip to content

Commit

Permalink
feat(onLongPress): new function (vitest-dev#1225)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
Co-authored-by: Blackfaded <r.heinen@nanogiants.de>
Co-authored-by: René Heinen <rene.heinen@gmx.net>
  • Loading branch information
3 people committed Feb 8, 2022
1 parent 1829ce3 commit eed2889
Show file tree
Hide file tree
Showing 13 changed files with 429 additions and 112 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -7,7 +7,7 @@ Collection of essential Vue Composition Utilities
<a href="https://www.npmjs.com/package/@vueuse/core" target="__blank"><img src="https://img.shields.io/npm/v/@vueuse/core?color=a1b858&label=" alt="NPM version"></a>
<a href="https://www.npmjs.com/package/@vueuse/core" target="__blank"><img alt="NPM Downloads" src="https://img.shields.io/npm/dm/@vueuse/core?color=50a36f&label="></a>
<a href="https://vueuse.org" target="__blank"><img src="https://img.shields.io/static/v1?label=&message=docs%20%26%20demos&color=1e8a7a" alt="Docs & Demos"></a>
<img alt="Function Count" src="https://img.shields.io/badge/-183%20functions-13708a">
<img alt="Function Count" src="https://img.shields.io/badge/-185%20functions-13708a">
<br>
<a href="https://github.com/vueuse/vueuse" target="__blank"><img alt="GitHub stars" src="https://img.shields.io/github/stars/vueuse/vueuse?style=social"></a>
</p>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -53,7 +53,7 @@
"@vitest/ui": "^0.2.8",
"@vue/compiler-sfc": "^3.2.30",
"@vue/composition-api": "^1.4.6",
"@vue/test-utils": "^1.3.0",
"@vue/test-utils": "^2.0.0-rc.18",
"@vue/theme": "^1.0.0",
"axios": "^0.25.0",
"bumpp": "^7.1.1",
Expand Down
2 changes: 2 additions & 0 deletions packages/components/index.ts
@@ -1,5 +1,7 @@
export * from '../core/onClickOutside/component'
export * from '../core/onClickOutside/directive'
export * from '../core/onLongPress/component'
export * from '../core/onLongPress/directive'
export * from '../core/useActiveElement/component'
export * from '../core/useBattery/component'
export * from '../core/useBrowserLocation/component'
Expand Down
1 change: 1 addition & 0 deletions packages/core/index.ts
Expand Up @@ -4,6 +4,7 @@ export * from './computedInject'
export * from './createUnrefFn'
export * from './onClickOutside'
export * from './onKeyStroke'
export * from './onLongPress'
export * from './onStartTyping'
export * from './templateRef'
export * from './unrefElement'
Expand Down
28 changes: 28 additions & 0 deletions packages/core/onLongpress/component.ts
@@ -0,0 +1,28 @@
import { defineComponent, h, ref } from 'vue-demi'
import type { RenderableComponent } from '../types'
import type { OnLongPressOptions } from '.'
import { onLongPress } from '.'

export interface OnLongPressProps extends RenderableComponent {
options?: OnLongPressOptions
}

export const OnLongPress = defineComponent<OnLongPressProps>({
name: 'OnLongPress',
props: ['as', 'options'] as unknown as undefined,
emits: ['trigger'],
setup(props, { slots, emit }) {
const target = ref()
onLongPress(
target,
(e) => {
emit('trigger', e)
},
props.options,
)
return () => {
if (slots.default)
return h(props.as || 'div', { ref: target }, slots.default())
}
},
})
33 changes: 33 additions & 0 deletions packages/core/onLongpress/demo.vue
@@ -0,0 +1,33 @@
<script setup lang="ts">
import { ref } from 'vue-demi'
import { onLongPress } from '.'
const htmlRef = ref<HTMLElement | null>(null)
const htmlRefOptions = ref<HTMLElement | null>(null)
const longPressed = ref(false)
const onLongPressCallback = (e: PointerEvent) => {
longPressed.value = true
}
const reset = () => {
longPressed.value = false
}
onLongPress(htmlRef, onLongPressCallback)
onLongPress(htmlRefOptions, onLongPressCallback, { delay: 1000 })
</script>

<template>
<p>Long Pressed: {{ longPressed }}</p>
<button ref="htmlRef" class="ml-2 button small">
Press long (500ms)
</button>
<button ref="htmlRefOptions" class="ml-2 button small">
Press long (1000ms)
</button>
<button class="ml-2 button small" @click="reset">
Reset
</button>
</template>
91 changes: 91 additions & 0 deletions packages/core/onLongpress/directive.test.ts
@@ -0,0 +1,91 @@
import { defineComponent } from 'vue-demi'
import type { VueWrapper } from '@vue/test-utils'
import { mount } from '@vue/test-utils'
import { promiseTimeout } from '@vueuse/shared'

import { VOnLongPress } from './directive'
import type { OnLongPressOptions } from '.'

const App = defineComponent({
props: {
onLongPress: {
type: Function,
required: true,
},
options: {
type: Object,
required: false,
},
},

template: `<template>
<div data-test="element" v-if="options" v-on-longpress="{handler: onLongPress, options}">Press me</div>
<div data-test="element" v-else v-on-longpress="onLongPress">Press me</div>
</template>
`,
})

describe('vOnLongPress', () => {
let onLongPress = vi.fn()
let wrapper: VueWrapper<any>

describe('given no options', () => {
beforeEach(() => {
onLongPress = vi.fn()
wrapper = mount(App, {
props: {
onLongPress,
},
global: {
directives: {
'on-longpress': VOnLongPress,
},
},
})
})

it('should be defined', () => {
expect(wrapper).toBeDefined()
})

it('should trigger longpress after 500ms', async() => {
const element = wrapper.get('[data-test=element]')
await element.trigger('pointerdown')
await promiseTimeout(500)
expect(onLongPress).toHaveBeenCalledTimes(1)
})
})

describe('given options', () => {
beforeEach(() => {
onLongPress = vi.fn()
const options: OnLongPressOptions = {
delay: 1000,
}
wrapper = mount(App, {
props: {
onLongPress,
options,
},
global: {
directives: {
'on-longpress': VOnLongPress,
},
},
})
})

it('should be defined', () => {
expect(wrapper).toBeDefined()
})

it('should trigger longpress after 500ms', async() => {
const element = wrapper.get('[data-test=element]')
await element.trigger('pointerdown')
await promiseTimeout(500)
expect(onLongPress).toHaveBeenCalledTimes(0)
await promiseTimeout(500)
expect(onLongPress).toHaveBeenCalledTimes(1)
})
})
})
20 changes: 20 additions & 0 deletions packages/core/onLongpress/directive.ts
@@ -0,0 +1,20 @@
import type { FunctionDirective } from 'vue-demi'
import type { OnLongPressOptions } from '.'
import { onLongPress } from '.'

type BindingValueFunction = (evt: PointerEvent) => void

interface BindingValueObject {
handler: BindingValueFunction
options: OnLongPressOptions
}

export const VOnLongPress: FunctionDirective<
HTMLElement,
BindingValueFunction | BindingValueObject
> = (el, binding) => {
if (typeof binding.value === 'function')
onLongPress(el, binding.value)
else
onLongPress(el, binding.value.handler, binding.value.options)
}
110 changes: 110 additions & 0 deletions packages/core/onLongpress/index.md
@@ -0,0 +1,110 @@
---
category: Sensors
---

# onLongPress

Listen for a long press on an element.

## Usage

### As a hook

```html
<script setup lang="ts">
import { ref } from 'vue'
import { onLongPress } from '@vueuse/core'
const htmlRefHook = ref<HTMLElement | null>(null)
const longPressedHook = ref(false)
const onLongPressCallbackHook = (e: PointerEvent) => {
longPressedHook.value = true
}
const resetHook = () => {
longPressedHook.value = false
}
onLongPress(htmlRefHook, onLongPressCallbackHook)
</script>

<template>
<p>Long Pressed: {{ longPressedHook }}</p>

<button ref="htmlRefHook" class="ml-2 button small">
Press long
</button>

<button class="ml-2 button small" @click="resetHook">
Reset
</button>
</template>
```

### As a component

<LearnMoreComponents />

```html
<script setup lang="ts">
import { ref } from 'vue'
import { OnLongPress } from '@vueuse/components'
const longPressedComponent = ref(false)
const onLongPressCallbackComponent = (e: PointerEvent) => {
longPressedComponent.value = true
}
const resetComponent = () => {
longPressedComponent.value = false
}
</script>

<template>
<p>Long Pressed: {{ longPressedComponent }}</p>

<OnLongPress as="button" class="ml-2 button small" @trigger="onLongPressCallbackComponent">
Press long
</OnLongPress>

<button class="ml-2 button small" @click="resetComponent">
Reset
</button>
</template>
```

### As a directive

<LearnMoreComponents />

```html
<script setup lang="ts">
import { ref } from 'vue'
import { VOnLongPress } from '@vueuse/components'
const longPressedDirective = ref(false)
const onLongPressCallbackDirective = (e: PointerEvent) => {
longPressedDirective.value = true
}
const resetDirective = () => {
longPressedDirective.value = false
}
</script>

<template>
<p>Long Pressed: {{ longPressedDirective }}</p>

<button v-on-long-press="onLongPressCallbackDirective" class="ml-2 button small">
Press long
</button>

<button v-on-long-press="{handler: onLongPressCallbackDirective, {delay: 1000}}" class="ml-2 button small">
Press long (with options)
</button>

<button class="ml-2 button small" @click="resetDirective">
Reset
</button>
</template>
```
68 changes: 68 additions & 0 deletions packages/core/onLongpress/index.test.ts
@@ -0,0 +1,68 @@
import { promiseTimeout } from '@vueuse/shared'
import type { Ref } from 'vue-demi'
import { ref } from 'vue-demi'
import { onLongPress } from '.'

const pointerdownEvent = new PointerEvent('pointerdown')

describe('onLongPress', () => {
let element: Ref<HTMLElement>

beforeEach(() => {
element = ref(document.createElement('div'))
})

it('should be defined', () => {
expect(onLongPress).toBeDefined()
})

describe('given argument is ref', () => {
describe('given no options', () => {
it('should trigger longpress after 500ms', async() => {
const onLongPressCallback = vi.fn()
onLongPress(element, onLongPressCallback)
element.value.dispatchEvent(pointerdownEvent)
expect(onLongPressCallback).toHaveBeenCalledTimes(0)
await promiseTimeout(500)
expect(onLongPressCallback).toHaveBeenCalledTimes(1)
})
})

describe('given options', () => {
it('should trigger longpress after options.delay ms', async() => {
const onLongPressCallback = vi.fn()
onLongPress(element, onLongPressCallback, { delay: 1000 })
element.value.dispatchEvent(pointerdownEvent)
await promiseTimeout(500)
expect(onLongPressCallback).toHaveBeenCalledTimes(0)
await promiseTimeout(500)
expect(onLongPressCallback).toHaveBeenCalledTimes(1)
})
})
})

describe('given argument is no ref', () => {
describe('given no options', () => {
it('should trigger longpress after 500ms', async() => {
const onLongPressCallback = vi.fn()
onLongPress(element.value, onLongPressCallback)
element.value.dispatchEvent(pointerdownEvent)
expect(onLongPressCallback).toHaveBeenCalledTimes(0)
await promiseTimeout(500)
expect(onLongPressCallback).toHaveBeenCalledTimes(1)
})
})

describe('given options', () => {
it('should trigger longpress after options.delay ms', async() => {
const onLongPressCallback = vi.fn()
onLongPress(element.value, onLongPressCallback, { delay: 1000 })
element.value.dispatchEvent(pointerdownEvent)
await promiseTimeout(500)
expect(onLongPressCallback).toHaveBeenCalledTimes(0)
await promiseTimeout(500)
expect(onLongPressCallback).toHaveBeenCalledTimes(1)
})
})
})
})

0 comments on commit eed2889

Please sign in to comment.