Skip to content

Commit

Permalink
feat(onKeyStroke): support ignoring repeated stroke (#2652)
Browse files Browse the repository at this point in the history
  • Loading branch information
vaakian committed Mar 28, 2023
1 parent 0823d68 commit 22ca513
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 9 deletions.
13 changes: 7 additions & 6 deletions packages/core/onKeyStroke/demo.vue
Expand Up @@ -5,21 +5,21 @@ import { onKeyStroke } from '@vueuse/core'
const translateX = ref(0)
const translateY = ref(0)
onKeyStroke(['w', 'W', 'ArrowUp'], (e: KeyboardEvent) => {
onKeyStroke(['w', 'W', 'ArrowUp'], () => {
translateY.value -= 10
})
onKeyStroke(['s', 'S', 'ArrowDown'], (e: KeyboardEvent) => {
onKeyStroke(['s', 'S', 'ArrowDown'], () => {
translateY.value += 10
})
onKeyStroke(['a', 'A', 'ArrowLeft'], (e: KeyboardEvent) => {
onKeyStroke(['a', 'A', 'ArrowLeft'], () => {
translateX.value -= 10
})
onKeyStroke(['d', 'D', 'ArrowRight'], (e: KeyboardEvent) => {
onKeyStroke(['d', 'D', 'ArrowRight'], () => {
translateX.value += 10
})
}, { dedupe: true })
</script>

<template>
Expand All @@ -28,7 +28,8 @@ onKeyStroke(['d', 'D', 'ArrowRight'], (e: KeyboardEvent) => {
<div class="ball" :style="{ transform: `translate(${translateX}px, ${translateY}px)` }" />
</div>
<div class="text-center mt-4">
Use the arrow keys or w a s d keys to control the movement of the ball.
<p>Use the arrow keys or w a s d keys to control the movement of the ball.</p>
<p>Repeated events are ignored on the key `d` or `->`.</p>
</div>
</div>
</template>
Expand Down
15 changes: 15 additions & 0 deletions packages/core/onKeyStroke/index.md
Expand Up @@ -44,6 +44,21 @@ onKeyStroke('A', (e) => {
}, { target: document })
```

### Ignore Repeated Events

The callback will trigger only once when pressing `A` and **hold down**.

```js
import { onKeyStroke, onKeyStrokeOnce } from '@vueuse/core'

// use `autoRepeat` option
onKeyStroke('A', (e) => {
console.log('Key A pressed')
}, { autoRepeat: false })
```

Reference: [KeyboardEvent.repeat](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat)

## Directive Usage

```html
Expand Down
13 changes: 11 additions & 2 deletions packages/core/onKeyStroke/index.test.ts
Expand Up @@ -13,8 +13,8 @@ describe('onKeyStroke', () => {
callBackFn = vi.fn()
})

function createKeyEvent(key: string, type: KeyStrokeEventName) {
const ev = new KeyboardEvent(type, { key })
function createKeyEvent(key: string, type: KeyStrokeEventName, repeat = false) {
const ev = new KeyboardEvent(type, { key, repeat })
element.value.dispatchEvent(ev)
}

Expand Down Expand Up @@ -73,4 +73,13 @@ describe('onKeyStroke', () => {
createKeyEvent('B', 'keypress')
expect(callBackFn).toBeCalledTimes(1)
})

it('ignore repeated events', () => {
onKeyStroke('A', callBackFn, { target: element, dedupe: true })
createKeyEvent('A', 'keydown', false)
createKeyEvent('A', 'keydown', true)
createKeyEvent('A', 'keydown', true)
createKeyEvent('A', 'keydown', true)
expect(callBackFn).toBeCalledTimes(1)
})
})
17 changes: 16 additions & 1 deletion packages/core/onKeyStroke/index.ts
@@ -1,4 +1,5 @@
import type { MaybeComputedRef } from '@vueuse/shared'
import { resolveUnref } from '@vueuse/shared'
import { useEventListener } from '../useEventListener'
import { defaultWindow } from '../_configurable'

Expand All @@ -9,6 +10,12 @@ export interface OnKeyStrokeOptions {
eventName?: KeyStrokeEventName
target?: MaybeComputedRef<EventTarget | null | undefined>
passive?: boolean
/**
* Set to `true` to ignore repeated events when the key is being held down.
*
* @default false
*/
dedupe?: MaybeComputedRef<boolean>
}

const createKeyPredicate = (keyFilter: KeyFilter): KeyPredicate => {
Expand Down Expand Up @@ -60,9 +67,17 @@ export function onKeyStroke(...args: any[]) {
handler = args[0]
}

const { target = defaultWindow, eventName = 'keydown', passive = false } = options
const {
target = defaultWindow,
eventName = 'keydown',
passive = false,
dedupe = false,
} = options
const predicate = createKeyPredicate(key)
const listener = (e: KeyboardEvent) => {
if (e.repeat && resolveUnref(dedupe))
return

if (predicate(e))
handler(e)
}
Expand Down

0 comments on commit 22ca513

Please sign in to comment.