Skip to content

Commit 950f48d

Browse files
committed
feat(useKey): Adding useKey function
1 parent 3d22ee0 commit 950f48d

File tree

8 files changed

+190
-0
lines changed

8 files changed

+190
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ Vue.use(VueCompositionAPI)
7272
- [`useIntersection`](./src/functions/useIntersection/stories/useIntersection.md) — tracks intersection of target element with an ancestor element.
7373
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-useintersection--demo)
7474
[![Demo](https://img.shields.io/badge/advanced_demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-useintersection--advanced-demo)
75+
- [`useKey`](./src/functions/useKey/stories/useKey.md) — executes a handler when a keyboard key is used.
76+
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-usekey--demo)
7577
- [`useLocation`](./src/functions/useLocation/stories/useLocation.md) — tracks bar navigation location state.
7678
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-uselocation--demo)
7779
- [`useMedia`](./src/functions/useMedia/stories/useMedia.md) — tracks state of a CSS media query.

src/functions/useKey/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './useKey'
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<template>
2+
<table class="table is-fullwidth">
3+
<thead>
4+
<tr>
5+
<th>Prop</th>
6+
<th>Value</th>
7+
</tr>
8+
</thead>
9+
<tbody>
10+
<tr>
11+
<td>isPressed</td>
12+
<td>{{ isPressed }}</td>
13+
</tr>
14+
<tr>
15+
<td>keyPressCount</td>
16+
<td>{{ keyPressCount }}</td>
17+
</tr>
18+
<tr>
19+
<td colspan="2">
20+
<button class="button is-primary" @click="start" v-if="!isTracking">
21+
Start tracking key press
22+
</button>
23+
<button class="button is-danger" @click="stop" v-else>
24+
Stop tracking key press
25+
</button>
26+
</td>
27+
</tr>
28+
</tbody>
29+
</table>
30+
</template>
31+
32+
<script lang="ts">
33+
import Vue from 'vue'
34+
import { watch, ref } from '@src/api'
35+
import { useKey } from '@src/vue-use-kit'
36+
37+
export default Vue.extend({
38+
name: 'UseKeyDemo',
39+
setup() {
40+
const keyPressCount = ref(0)
41+
const { isPressed, isTracking, start, stop } = useKey('g')
42+
43+
watch(isPressed, isPress => isPress && keyPressCount.value++)
44+
45+
return { keyPressCount, isPressed, isTracking, start, stop }
46+
}
47+
})
48+
</script>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# useKey
2+
3+
Vue function that executes a handler when a keyboard key is used.
4+
5+
## Reference
6+
7+
```typescript
8+
// function useKey()
9+
```
10+
11+
### Parameters
12+
13+
- `value: string` lorem ipsa
14+
15+
### Returns
16+
17+
- `value: Ref<string>` lorem ipsa
18+
19+
## Usage
20+
21+
```html
22+
<template></template>
23+
```
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { storiesOf } from '@storybook/vue'
2+
import path from 'path'
3+
import StoryTitle from '@src/helpers/StoryTitle.vue'
4+
import UseKeyDemo from './UseKeyDemo.vue'
5+
6+
const functionName = 'useKey'
7+
const functionPath = path.resolve(__dirname, '..')
8+
const notes = require(`./${functionName}.md`).default
9+
10+
const basicDemo = () => ({
11+
components: { StoryTitle, demo: UseKeyDemo },
12+
template: `
13+
<div class="container">
14+
<story-title
15+
function-path="${functionPath}"
16+
source-name="${functionName}"
17+
demo-name="UseKeyDemo.vue"
18+
>
19+
<template v-slot:title></template>
20+
<template v-slot:intro></template>
21+
</story-title>
22+
<demo />
23+
</div>`
24+
})
25+
26+
storiesOf('sensors|useKey', module)
27+
.addParameters({ notes })
28+
.add('Demo', basicDemo)

src/functions/useKey/useKey.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// import { mount } from '@src/helpers/test'
2+
// import { useKey } from '@src/vue-use-kit'
3+
4+
afterEach(() => {
5+
jest.clearAllMocks()
6+
})
7+
8+
describe('useKey', () => {
9+
it('should do something', () => {
10+
// Add test here
11+
})
12+
})

src/functions/useKey/useKey.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { ref, onMounted, onUnmounted, Ref } from '@src/api'
2+
3+
export type UseKeyFilter = string | ((event: KeyboardEvent) => boolean)
4+
export type UseKeyCallback = (event: KeyboardEvent) => void
5+
6+
export interface UseKeyOptions {
7+
callback?: UseKeyCallback
8+
triggerRef?: Ref<null | HTMLElement>
9+
triggerOnce?: boolean
10+
}
11+
12+
const defaultOptions = {
13+
callback: () => ``,
14+
triggerRef: { value: null },
15+
triggerOnce: false
16+
}
17+
18+
export function useKey(
19+
filter: UseKeyFilter,
20+
options?: UseKeyOptions,
21+
runOnMount = true
22+
) {
23+
const { callback, triggerRef, triggerOnce } = Object.assign(
24+
{},
25+
defaultOptions,
26+
options
27+
)
28+
const isTracking = ref(false)
29+
const isPressed = ref(false)
30+
31+
const getTriggerRef = (): any => triggerRef.value || document
32+
33+
const getFilter = () => {
34+
if (typeof filter === 'function') return filter
35+
return (event: KeyboardEvent) => event.key === filter
36+
}
37+
38+
const handleKeyDown = (event: KeyboardEvent) => {
39+
const filterFn = getFilter()
40+
if (!filterFn(event)) return
41+
42+
if (triggerOnce && isPressed.value) return
43+
isPressed.value = true
44+
callback(event)
45+
}
46+
47+
const handleKeyUp = (event: KeyboardEvent) => {
48+
const filterFn = getFilter()
49+
if (!filterFn(event)) return
50+
51+
isPressed.value = false
52+
callback(event)
53+
}
54+
55+
const start = () => {
56+
if (isTracking.value) return
57+
const $el = getTriggerRef()
58+
$el.addEventListener('keydown', handleKeyDown)
59+
$el.addEventListener('keyup', handleKeyUp)
60+
isTracking.value = true
61+
}
62+
63+
const stop = () => {
64+
if (!isTracking.value) return
65+
const $el = getTriggerRef()
66+
$el.removeEventListener('keydown', handleKeyDown)
67+
$el.removeEventListener('keyup', handleKeyUp)
68+
isTracking.value = false
69+
}
70+
71+
onMounted(() => runOnMount && start())
72+
onUnmounted(stop)
73+
74+
return { isPressed, isTracking, start, stop }
75+
}

src/vue-use-kit.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export * from './functions/useGeolocation'
88
export * from './functions/useHover'
99
export * from './functions/useIdle'
1010
export * from './functions/useIntersection'
11+
export * from './functions/useKey'
1112
export * from './functions/useLocation'
1213
export * from './functions/useMedia'
1314
export * from './functions/useMediaDevices'

0 commit comments

Comments
 (0)