From 57a46ee9845bade08d5a190ff80edb2ae3f1a533 Mon Sep 17 00:00:00 2001 From: azaleta <24407500@qq.com> Date: Wed, 14 Sep 2022 14:01:28 +0900 Subject: [PATCH] refact(onKeyStroke): improve type --- packages/core/onKeyStroke/directive.ts | 2 +- packages/core/onKeyStroke/index.md | 9 +++ packages/core/onKeyStroke/index.test.ts | 76 +++++++++++++++++++++++++ packages/core/onKeyStroke/index.ts | 43 ++++++++++---- 4 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 packages/core/onKeyStroke/index.test.ts diff --git a/packages/core/onKeyStroke/directive.ts b/packages/core/onKeyStroke/directive.ts index d365b31c434..6b7cfb52316 100644 --- a/packages/core/onKeyStroke/directive.ts +++ b/packages/core/onKeyStroke/directive.ts @@ -12,7 +12,7 @@ HTMLElement, BindingValueFunction | BindingValueArray > = { [directiveHooks.mounted](el, binding) { - const keys = binding.arg?.split(',') ?? [] + const keys = binding.arg?.split(',') ?? true if (typeof binding.value === 'function') { onKeyStroke(keys, binding.value, { target: el, diff --git a/packages/core/onKeyStroke/index.md b/packages/core/onKeyStroke/index.md index 18e292cbc36..ff08a0adbd4 100644 --- a/packages/core/onKeyStroke/index.md +++ b/packages/core/onKeyStroke/index.md @@ -26,6 +26,15 @@ import { onKeyStroke } from '@vueuse/core' onKeyStroke(['s', 'S', 'ArrowDown'], (e) => { e.preventDefault() }) + +// listen to all keys by [true / skip the keyDefine] +onKeyStroke(true, (e) => { + e.preventDefault() +}) +onKeyStroke((e) => { + e.preventDefault() +}) + ``` ### Custom Event Target diff --git a/packages/core/onKeyStroke/index.test.ts b/packages/core/onKeyStroke/index.test.ts new file mode 100644 index 00000000000..35392f118ae --- /dev/null +++ b/packages/core/onKeyStroke/index.test.ts @@ -0,0 +1,76 @@ +import { vi } from 'vitest' +import type { Ref } from 'vue-demi' +import { ref } from 'vue-demi' +import type { KeyStrokeEventName } from '.' +import { onKeyStroke } from '.' + +describe('onKeyStroke', () => { + let element: Ref + let callBackFn: any + + beforeEach(() => { + element = ref(document.createElement('div')) + callBackFn = vi.fn() + }) + + function createKeyEvent(key: string, type: KeyStrokeEventName) { + const ev = new KeyboardEvent(type, { key }) + element.value.dispatchEvent(ev) + } + + it('listen to single key', () => { + onKeyStroke('A', callBackFn, { target: element }) + createKeyEvent('A', 'keydown') + createKeyEvent('B', 'keydown') + expect(callBackFn).toBeCalledTimes(1) + }) + + it('listen to multi keys', () => { + onKeyStroke(['A', 'B', 'C'], callBackFn, { target: element }) + createKeyEvent('A', 'keydown') + createKeyEvent('B', 'keydown') + createKeyEvent('C', 'keydown') + createKeyEvent('D', 'keydown') + expect(callBackFn).toBeCalledTimes(3) + }) + + it('use function filter', () => { + const filter = (event: KeyboardEvent) => { + return event.key === 'A' + } + onKeyStroke(filter, callBackFn, { target: element }) + createKeyEvent('A', 'keydown') + createKeyEvent('B', 'keydown') + createKeyEvent('C', 'keydown') + expect(callBackFn).toBeCalledTimes(1) + }) + + it('listen to all keys by boolean', () => { + onKeyStroke(true, callBackFn, { target: element }) + createKeyEvent('A', 'keydown') + createKeyEvent('B', 'keydown') + createKeyEvent('C', 'keydown') + createKeyEvent('D', 'keydown') + createKeyEvent('E', 'keydown') + expect(callBackFn).toBeCalledTimes(5) + }) + + it('listen to all keys by constructor', () => { + onKeyStroke(callBackFn, { target: element }) + createKeyEvent('A', 'keydown') + createKeyEvent('B', 'keydown') + createKeyEvent('C', 'keydown') + createKeyEvent('D', 'keydown') + createKeyEvent('E', 'keydown') + expect(callBackFn).toBeCalledTimes(5) + }) + + it('listen to keypress', () => { + onKeyStroke('A', callBackFn, { target: element, eventName: 'keypress' }) + createKeyEvent('A', 'keydown') + createKeyEvent('B', 'keydown') + createKeyEvent('A', 'keypress') + createKeyEvent('B', 'keypress') + expect(callBackFn).toBeCalledTimes(1) + }) +}) diff --git a/packages/core/onKeyStroke/index.ts b/packages/core/onKeyStroke/index.ts index 427007497b7..be4ebec7123 100644 --- a/packages/core/onKeyStroke/index.ts +++ b/packages/core/onKeyStroke/index.ts @@ -3,7 +3,7 @@ import { useEventListener } from '../useEventListener' import { defaultWindow } from '../_configurable' export type KeyPredicate = (event: KeyboardEvent) => boolean -export type KeyFilter = null | undefined | string | string[] | KeyPredicate +export type KeyFilter = true | string | string[] | KeyPredicate export type KeyStrokeEventName = 'keydown' | 'keypress' | 'keyup' export interface OnKeyStrokeOptions { eventName?: KeyStrokeEventName @@ -21,22 +21,45 @@ const createKeyPredicate = (keyFilter: KeyFilter): KeyPredicate => { else if (Array.isArray(keyFilter)) return (event: KeyboardEvent) => keyFilter.includes(event.key) - else if (keyFilter) - return () => true - - else - return () => false + return () => true } +export function onKeyStroke(key: KeyFilter, handler: (event: KeyboardEvent) => void, options?: OnKeyStrokeOptions): () => void +export function onKeyStroke(handler: (event: KeyboardEvent) => void, options?: OnKeyStrokeOptions): () => void + /** * Listen for keyboard keys being stroked. * * @see https://vueuse.org/onKeyStroke - * @param key - * @param handler - * @param options */ -export function onKeyStroke(key: KeyFilter, handler: (event: KeyboardEvent) => void, options: OnKeyStrokeOptions = {}) { +export function onKeyStroke(key: KeyFilter, handler: (event: KeyboardEvent) => void, options?: OnKeyStrokeOptions): () => void +export function onKeyStroke(handler: (event: KeyboardEvent) => void, options?: OnKeyStrokeOptions): () => void +export function onKeyStroke(...args: any[]) { + let key: KeyFilter + let handler: (event: KeyboardEvent) => void + let options: OnKeyStrokeOptions = {} + + if (args.length === 3) { + key = args[0] + handler = args[1] + options = args[2] + } + else if (args.length === 2) { + if (typeof args[1] === 'object') { + key = true + handler = args[0] + options = args[1] + } + else { + key = args[0] + handler = args[1] + } + } + else { + key = true + handler = args[0] + } + const { target = defaultWindow, eventName = 'keydown', passive = false } = options const predicate = createKeyPredicate(key) const listener = (e: KeyboardEvent) => {