diff --git a/.changeset/hot-islands-carry.md b/.changeset/hot-islands-carry.md new file mode 100644 index 00000000..fc884afd --- /dev/null +++ b/.changeset/hot-islands-carry.md @@ -0,0 +1,5 @@ +--- +"@vue-flow/core": patch +--- + +Properly release key combinations when one of the keys is unpressed diff --git a/packages/core/src/composables/useKeyPress.ts b/packages/core/src/composables/useKeyPress.ts index e3c7602c..a38afdf7 100644 --- a/packages/core/src/composables/useKeyPress.ts +++ b/packages/core/src/composables/useKeyPress.ts @@ -3,6 +3,9 @@ import { onMounted, ref, toRef, toValue, watch } from 'vue' import type { KeyFilter, KeyPredicate } from '@vueuse/core' import { onKeyStroke, useEventListener } from '@vueuse/core' +type PressedKeys = Set +type KeyOrCode = 'key' | 'code' + export interface UseKeyPressOptions { actInsideInputWithModifier?: MaybeRefOrGetter target?: MaybeRefOrGetter @@ -35,18 +38,23 @@ function isKeyMatch(pressedKey: string, keyToMatch: string, pressedKeys: Set pressedKeys.has(key) && Array.from(pressedKeys.values())[index] === keyCombination[index], ) + + if (isKeyUp) { + pressedKeys.delete(pressedKey.toLowerCase()) + } + + return isMatch } -function createKeyPredicate(keyFilter: string | string[], pressedKeys: Set): KeyPredicate { +function createKeyPredicate(keyFilter: string | string[], pressedKeys: PressedKeys): KeyPredicate { return (event: KeyboardEvent) => { if (!event.code && !event.key) { return false @@ -54,24 +62,17 @@ function createKeyPredicate(keyFilter: string | string[], pressedKeys: Set isKeyMatch(pressedKey, key, pressedKeys, isKeyUp)) + return keyFilter.some((key) => isKeyMatch(event[keyOrCode], key, pressedKeys, event.type === 'keyup')) } // if the keyFilter is a string, we need to check if the key matches the string - return isKeyMatch(pressedKey, keyFilter, pressedKeys, isKeyUp) + return isKeyMatch(event[keyOrCode], keyFilter, pressedKeys, event.type === 'keyup') } } -function useKeyOrCode(code: string, keysToWatch: string | string[]) { - if (typeof keysToWatch === 'string') { - return code === keysToWatch ? 'code' : 'key' - } - +function useKeyOrCode(code: string, keysToWatch: string | string[]): KeyOrCode { return keysToWatch.includes(code) ? 'code' : 'key' } @@ -133,9 +134,7 @@ export function useKeyPress(keyFilter: MaybeRefOrGetter { - return currentFilter(...args) - }, + (...args) => currentFilter(...args), (e) => { if (isPressed.value) { const preventAction = (!modifierPressed || (modifierPressed && !actInsideInputWithModifier.value)) && isInputDOMNode(e) @@ -144,7 +143,8 @@ export function useKeyPress(keyFilter: MaybeRefOrGetter