From d51499de96153c19a88fe906d5129889d00aaca0 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Tue, 17 Jan 2023 21:18:56 +0100 Subject: [PATCH] refactor(core): support key combinations for key codes Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- packages/core/src/composables/useKeyPress.ts | 50 ++++++++++++++++---- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/packages/core/src/composables/useKeyPress.ts b/packages/core/src/composables/useKeyPress.ts index a42ed893..dc623329 100644 --- a/packages/core/src/composables/useKeyPress.ts +++ b/packages/core/src/composables/useKeyPress.ts @@ -1,13 +1,10 @@ import type { Ref } from 'vue' -import type { KeyFilter, MaybeRef } from '@vueuse/core' +import type { KeyFilter, KeyPredicate, MaybeRef } from '@vueuse/core' import { isBoolean, isFunction } from '@vueuse/core' export function isInputDOMNode(event: KeyboardEvent): boolean { const target = (event.composedPath?.()?.[0] || event.target) as HTMLElement - // we want to be able to do a multi selection event if we are in an input field - if (event.ctrlKey || event.metaKey || event.shiftKey) return false - const hasAttribute = isFunction(target.hasAttribute) ? target.hasAttribute('contenteditable') : false const closest = isFunction(target.closest) ? target.closest('.nokey') : null @@ -16,17 +13,40 @@ export function isInputDOMNode(event: KeyboardEvent): boolean { return ['INPUT', 'SELECT', 'TEXTAREA'].includes(target?.nodeName) || hasAttribute || !!closest } +// we want to be able to do a multi selection event if we are in an input field +function wasModifierPressed(event: KeyboardEvent) { + return event.ctrlKey || event.metaKey || event.shiftKey +} + +function createKeyPredicate(keyFilter: KeyFilter, pressedKeys: Set): KeyPredicate { + return (event: KeyboardEvent) => + (keyFilter as string[]).some((key) => { + const keyCombination = key.split('+').map((k) => k.trim().toLowerCase()) + + if (keyCombination.length === 1) { + return event.key === key + } else { + pressedKeys.add(event.key.toLowerCase()) + return keyCombination.every((key) => pressedKeys.has(key)) + } + }) +} + export default (keyFilter: MaybeRef, onChange?: (keyPressed: boolean) => void): Ref => { const window = useWindow() let isPressed = $ref(unref(keyFilter) === true) + let modifierPressed = $ref(false) + + const pressedKeys = $ref>(new Set()) + watch($$(isPressed), () => { if (onChange && typeof onChange === 'function') onChange(isPressed) }) watchEffect(() => { - const unrefKeyFilter = unref(keyFilter) + let unrefKeyFilter = unref(keyFilter) if (typeof window.addEventListener !== 'undefined') { useEventListener(window, 'blur', () => { @@ -39,11 +59,17 @@ export default (keyFilter: MaybeRef, onChange?: (keyPressed: b return } + if (Array.isArray(unrefKeyFilter)) { + unrefKeyFilter = createKeyPredicate(unrefKeyFilter, pressedKeys) + } + if (unrefKeyFilter) { onKeyStroke( unrefKeyFilter, (e) => { - if (isInputDOMNode(e)) return + modifierPressed = wasModifierPressed(e) + + if (!modifierPressed && isInputDOMNode(e)) return e.preventDefault() @@ -54,8 +80,16 @@ export default (keyFilter: MaybeRef, onChange?: (keyPressed: b onKeyStroke( unrefKeyFilter, - () => { - isPressed = false + (e) => { + if (isPressed) { + if (!modifierPressed && isInputDOMNode(e)) return + + modifierPressed = false + + pressedKeys.clear() + + isPressed = false + } }, { eventName: 'keyup' }, )