Skip to content

Commit

Permalink
feat: add useKey function.
Browse files Browse the repository at this point in the history
  • Loading branch information
yang committed Apr 4, 2021
1 parent 1fbb7e1 commit b3cd933
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 0 deletions.
7 changes: 7 additions & 0 deletions indexes.json
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,13 @@
"category": "Sensors",
"description": "detects that a target element's visibility"
},
{
"name": "useKey",
"package": "core",
"docs": "https://vueuse.org/core/useKey/",
"category": "Sensors",
"description": "listen for keyboard keys being used."
},
{
"name": "useLocalStorage",
"package": "core",
Expand Down
59 changes: 59 additions & 0 deletions packages/core/useKey/demo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<script setup lang="ts">
import { ref } from 'vue-demi'
import { useKey } from '.'
const translateX = ref(0)
const translateY = ref(0)
useKey('ArrowUp', (e: KeyboardEvent) => {
translateY.value -= 10
e.preventDefault()
})
useKey('ArrowDown', (e: KeyboardEvent) => {
translateY.value += 10
e.preventDefault()
})
useKey('ArrowLeft', (e: KeyboardEvent) => {
translateX.value -= 10
e.preventDefault()
})
useKey('ArrowRight', (e: KeyboardEvent) => {
translateX.value += 10
e.preventDefault()
})
</script>

<template>
<div>
<div class="container">
<div class="ball" :style="{transform: `translate(${translateX}px, ${translateY}px)`}" />
</div>
<div class="text-center mt-4">
Use the arrow keys to control the movement of the ball.
</div>
</div>
</template>

<style scoped>
.container {
display: flex;
justify-content: center;
align-items: center;
width: 400px;
height: 100px;
margin: auto;
overflow: hidden;
border: 1px solid #333;
}
.ball {
width: 16px;
height: 16px;
background: #333;
border-radius: 50%;
}
</style>
61 changes: 61 additions & 0 deletions packages/core/useKey/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
category: Sensors
---

# useKey
Listen for keyboard keys being used.

## Usage

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

useKey('ArrowDown', (e) => {
e.preventDefault()
})
```

Custom Event Target

```js
useKey(document, 'ArrowDown', (e) => {
e.preventDefault()
})
```

Custom Keyboard Event
```js
useKey('ArrowDown', (e) => {
e.preventDefault()
}, 'keyUp')
```

## Type Declarations

```typescript
export type KeyPredicate = (event: KeyboardEvent) => boolean
export type KeyFilter = null | undefined | string | ((event: KeyboardEvent) => boolean)
export type Handler = (event: KeyboardEvent) => void
export type EventType = 'keydown' | 'keypress' | 'keyup'

export function useKey(
target: MaybeRef<EventTarget | null | undefined>,
key: KeyFilter,
handler: Handler,
event?: EventType,
options?: boolean | AddEventListenerOptions
): Fn

export function useKey(
key: KeyFilter,
handler: Handler,
event?: EventType,
options?: boolean | AddEventListenerOptions
): Fn
```

## Source

[Source](https://github.com/vueuse/vueuse/blob/main/packages/core/useKey/index.ts) • [Docs](https://github.com/vueuse/vueuse/blob/main/packages/core/useKey/index.md)

<!--FOOTER_ENDS-->
59 changes: 59 additions & 0 deletions packages/core/useKey/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
useEventListener,
} from '../useEventListener'
import { defaultWindow } from '../_configurable'
import { Fn, isFunction, isString, MaybeRef } from '@vueuse/shared'

export type KeyPredicate = (event: KeyboardEvent) => boolean
export type KeyFilter = null | undefined | string | ((event: KeyboardEvent) => boolean)
export type Handler = (event: KeyboardEvent) => void
export type EventType = 'keydown' | 'keypress' | 'keyup'

const createKeyPredicate = (keyFilter: KeyFilter): KeyPredicate =>
typeof keyFilter === 'function'
? keyFilter
: typeof keyFilter === 'string'
? (event: KeyboardEvent) => event.key === keyFilter
: keyFilter
? () => true
: () => false

export function useKey(
target: MaybeRef<EventTarget | null | undefined>,
key: KeyFilter,
handler: Handler,
event?: EventType,
options?: boolean | AddEventListenerOptions
): Fn

export function useKey(
key: KeyFilter,
handler: Handler,
event?: EventType,
options?: boolean | AddEventListenerOptions
): Fn

export function useKey(...args: any[]) {
let target: MaybeRef<EventTarget> | undefined
let key: KeyFilter
let handler: any
let eventName: EventType
let options: any

if (isString(args[0]) || isFunction(args[0])) {
[key, handler, eventName = 'keydown', options] = args
target = defaultWindow
}
else {
[target, key, handler, eventName = 'keydown', options] = args
target = defaultWindow
}

const predicate = createKeyPredicate(key)
const listener = (e: KeyboardEvent) => {
if (predicate(e))
handler(e)
}

return useEventListener(target, eventName, listener, options)
}
1 change: 1 addition & 0 deletions packages/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
- [`useGeolocation`](https://vueuse.org/core/useGeolocation/) — reactive [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API)
- [`useIdle`](https://vueuse.org/core/useIdle/) — tracks whether the user is being inactive
- [`useIntersectionObserver`](https://vueuse.org/core/useIntersectionObserver/) — detects that a target element's visibility
- [`useKey`](https://vueuse.org/core/useKey/) — listen for keyboard keys being used.
- [`useMouse`](https://vueuse.org/core/useMouse/) — reactive mouse position
- [`useMouseInElement`](https://vueuse.org/core/useMouseInElement/) — reactive mouse position related to an element
- [`useMousePressed`](https://vueuse.org/core/useMousePressed/) — reactive mouse pressing state
Expand Down

0 comments on commit b3cd933

Please sign in to comment.