react-hotkeys-hook 4.4.2 → 5.0.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-hotkeys-hook.esm.js","sources":["../src/parseHotkeys.ts","../src/isHotkeyPressed.ts","../src/validators.ts","../src/BoundHotkeysProxyProvider.tsx","../src/deepEqual.ts","../src/HotkeysProvider.tsx","../src/useDeepEqualMemo.ts","../src/useHotkeys.ts","../src/useRecordHotkeys.ts"],"sourcesContent":["import { Hotkey, KeyboardModifiers } from './types'\n\nconst reservedModifierKeywords = ['shift', 'alt', 'meta', 'mod', 'ctrl']\n\nconst mappedKeys: Record<string, string> = {\n esc: 'escape',\n return: 'enter',\n left: 'arrowleft',\n right: 'arrowright',\n up: 'arrowup',\n down: 'arrowdown',\n space: ' ',\n ShiftLeft: 'shift',\n ShiftRight: 'shift',\n AltLeft: 'alt',\n AltRight: 'alt',\n MetaLeft: 'meta',\n MetaRight: 'meta',\n OSLeft: 'meta',\n OSRight: 'meta',\n ControlLeft: 'ctrl',\n ControlRight: 'ctrl',\n}\n\nexport function mapKey(key: string): string {\n return (mappedKeys[key.trim()] || key.trim()).toLowerCase().replace(/key|digit|numpad/, '')\n}\n\nexport function isHotkeyModifier(key: string) {\n return reservedModifierKeywords.includes(key)\n}\n\nexport function parseKeysHookInput(keys: string, splitKey = ','): string[] {\n return keys.split(splitKey)\n}\n\nexport function parseHotkey(hotkey: string, combinationKey = '+', description?: string): Hotkey {\n const keys = hotkey\n .toLocaleLowerCase()\n .split(combinationKey)\n .map((k) => mapKey(k))\n\n const modifiers: KeyboardModifiers = {\n alt: keys.includes('alt'),\n ctrl: keys.includes('ctrl') || keys.includes('control'),\n shift: keys.includes('shift'),\n meta: keys.includes('meta'),\n mod: keys.includes('mod'),\n }\n\n const singleCharKeys = keys.filter((k) => !reservedModifierKeywords.includes(k))\n\n return {\n ...modifiers,\n keys: singleCharKeys,\n description,\n }\n}\n","import { isHotkeyModifier, mapKey } from './parseHotkeys'\n;(() => {\n if (typeof document !== 'undefined') {\n document.addEventListener('keydown', (e) => {\n if (e.key === undefined) {\n // Synthetic event (e.g., Chrome autofill). Ignore.\n return\n }\n\n console.log('keydown', e.key, mapKey(e.key), e.key.length)\n\n pushToCurrentlyPressedKeys([mapKey(e.key)])\n })\n\n document.addEventListener('keyup', (e) => {\n if (e.key === undefined) {\n // Synthetic event (e.g., Chrome autofill). Ignore.\n return\n }\n\n removeFromCurrentlyPressedKeys([mapKey(e.key)])\n })\n }\n\n if (typeof window !== 'undefined') {\n window.addEventListener('blur', () => {\n currentlyPressedKeys.clear()\n })\n }\n})()\n\nconst currentlyPressedKeys: Set<string> = new Set<string>()\n\n// https://github.com/microsoft/TypeScript/issues/17002\nexport function isReadonlyArray(value: unknown): value is readonly unknown[] {\n return Array.isArray(value)\n}\n\nexport function isHotkeyPressed(key: string | readonly string[], splitKey = ','): boolean {\n const hotkeyArray = isReadonlyArray(key) ? key : key.split(splitKey)\n\n return hotkeyArray.every((hotkey) => currentlyPressedKeys.has(hotkey.trim().toLowerCase()))\n}\n\nexport function pushToCurrentlyPressedKeys(key: string | string[]): void {\n const hotkeyArray = Array.isArray(key) ? key : [key]\n\n /*\n Due to a weird behavior on macOS we need to clear the set if the user pressed down the meta key and presses another key.\n https://stackoverflow.com/questions/11818637/why-does-javascript-drop-keyup-events-when-the-metakey-is-pressed-on-mac-browser\n Otherwise the set will hold all ever pressed keys while the meta key is down which leads to wrong results.\n */\n if (currentlyPressedKeys.has('meta')) {\n currentlyPressedKeys.forEach((key) => !isHotkeyModifier(key) && currentlyPressedKeys.delete(key.toLowerCase()))\n }\n\n hotkeyArray.forEach((hotkey) => currentlyPressedKeys.add(hotkey.toLowerCase()))\n}\n\nexport function removeFromCurrentlyPressedKeys(key: string | string[]): void {\n const hotkeyArray = Array.isArray(key) ? key : [key]\n\n /*\n Due to a weird behavior on macOS we need to clear the set if the user pressed down the meta key and presses another key.\n https://stackoverflow.com/questions/11818637/why-does-javascript-drop-keyup-events-when-the-metakey-is-pressed-on-mac-browser\n Otherwise the set will hold all ever pressed keys while the meta key is down which leads to wrong results.\n */\n if (key === 'meta') {\n currentlyPressedKeys.clear()\n } else {\n hotkeyArray.forEach((hotkey) => currentlyPressedKeys.delete(hotkey.toLowerCase()))\n }\n}\n","import { FormTags, Hotkey, Scopes, Trigger } from './types'\nimport { isHotkeyPressed, isReadonlyArray } from './isHotkeyPressed'\n\nexport function maybePreventDefault(e: KeyboardEvent, hotkey: Hotkey, preventDefault?: Trigger): void {\n if ((typeof preventDefault === 'function' && preventDefault(e, hotkey)) || preventDefault === true) {\n e.preventDefault()\n }\n}\n\nexport function isHotkeyEnabled(e: KeyboardEvent, hotkey: Hotkey, enabled?: Trigger): boolean {\n if (typeof enabled === 'function') {\n return enabled(e, hotkey)\n }\n\n return enabled === true || enabled === undefined\n}\n\nexport function isKeyboardEventTriggeredByInput(ev: KeyboardEvent): boolean {\n return isHotkeyEnabledOnTag(ev, ['input', 'textarea', 'select'])\n}\n\nexport function isHotkeyEnabledOnTag(\n { target }: KeyboardEvent,\n enabledOnTags: readonly FormTags[] | boolean = false\n): boolean {\n const targetTagName = target && (target as HTMLElement).tagName\n\n if (isReadonlyArray(enabledOnTags)) {\n return Boolean(\n targetTagName && enabledOnTags && enabledOnTags.some((tag) => tag.toLowerCase() === targetTagName.toLowerCase())\n )\n }\n\n return Boolean(targetTagName && enabledOnTags && enabledOnTags === true)\n}\n\nexport function isScopeActive(activeScopes: string[], scopes?: Scopes): boolean {\n if (activeScopes.length === 0 && scopes) {\n console.warn(\n 'A hotkey has the \"scopes\" option set, however no active scopes were found. If you want to use the global scopes feature, you need to wrap your app in a <HotkeysProvider>'\n )\n\n return true\n }\n\n if (!scopes) {\n return true\n }\n\n return activeScopes.some((scope) => scopes.includes(scope)) || activeScopes.includes('*')\n}\n\nexport const isHotkeyMatchingKeyboardEvent = (e: KeyboardEvent, hotkey: Hotkey, ignoreModifiers = false): boolean => {\n const { alt, meta, mod, shift, ctrl, keys } = hotkey\n const { key: pressedKeyUppercase, ctrlKey, metaKey, shiftKey, altKey } = e\n\n const pressedKey = pressedKeyUppercase.toLowerCase()\n\n if (\n !keys?.includes(pressedKey) &&\n !['ctrl', 'control', 'unknown', 'meta', 'alt', 'shift', 'os'].includes(pressedKey)\n ) {\n return false\n }\n\n if (!ignoreModifiers) {\n // We check the pressed keys for compatibility with the keyup event. In keyup events the modifier flags are not set.\n if (alt === !altKey && pressedKey !== 'alt') {\n return false\n }\n\n if (shift === !shiftKey && pressedKey !== 'shift') {\n return false\n }\n\n // Mod is a special key name that is checking for meta on macOS and ctrl on other platforms\n if (mod) {\n if (!metaKey && !ctrlKey) {\n return false\n }\n } else {\n if (meta === !metaKey && pressedKey !== 'meta' && pressedKey !== 'os') {\n return false\n }\n\n if (ctrl === !ctrlKey && pressedKey !== 'ctrl' && pressedKey !== 'control') {\n return false\n }\n }\n }\n\n // All modifiers are correct, now check the key\n // If the key is set, we check for the key\n if (keys && keys.length === 1 && keys.includes(pressedKey)) {\n return true\n } else if (keys) {\n // Check if all keys are present in pressedDownKeys set\n return isHotkeyPressed(keys)\n } else if (!keys) {\n // If the key is not set, we only listen for modifiers, that check went alright, so we return true\n return true\n }\n\n // There is nothing that matches.\n return false\n}\n","import { createContext, ReactNode, useContext } from 'react'\nimport { Hotkey } from './types'\n\ntype BoundHotkeysProxyProviderType = {\n addHotkey: (hotkey: Hotkey) => void\n removeHotkey: (hotkey: Hotkey) => void\n}\n\nconst BoundHotkeysProxyProvider = createContext<BoundHotkeysProxyProviderType | undefined>(undefined)\n\nexport const useBoundHotkeysProxy = () => {\n return useContext(BoundHotkeysProxyProvider)\n}\n\ninterface Props {\n children: ReactNode\n addHotkey: (hotkey: Hotkey) => void\n removeHotkey: (hotkey: Hotkey) => void\n}\n\nexport default function BoundHotkeysProxyProviderProvider({ addHotkey, removeHotkey, children }: Props) {\n return (\n <BoundHotkeysProxyProvider.Provider value={{ addHotkey, removeHotkey }}>\n {children}\n </BoundHotkeysProxyProvider.Provider>\n )\n}\n","export default function deepEqual(x: any, y: any): boolean {\n //@ts-ignore\n return x && y && typeof x === 'object' && typeof y === 'object'\n ? Object.keys(x).length === Object.keys(y).length &&\n //@ts-ignore\n Object.keys(x).reduce((isEqual, key) => isEqual && deepEqual(x[key], y[key]), true)\n : x === y\n}\n","import { Hotkey } from './types'\nimport { createContext, ReactNode, useState, useContext, useCallback } from 'react'\nimport BoundHotkeysProxyProviderProvider from './BoundHotkeysProxyProvider'\nimport deepEqual from './deepEqual'\n\nexport type HotkeysContextType = {\n hotkeys: ReadonlyArray<Hotkey>\n activeScopes: string[]\n toggleScope: (scope: string) => void\n enableScope: (scope: string) => void\n disableScope: (scope: string) => void\n}\n\n// The context is only needed for special features like global scoping, so we use a graceful default fallback\nconst HotkeysContext = createContext<HotkeysContextType>({\n hotkeys: [],\n activeScopes: [], // This array has to be empty instead of containing '*' as default, to check if the provider is set or not\n toggleScope: () => {},\n enableScope: () => {},\n disableScope: () => {},\n})\n\nexport const useHotkeysContext = () => {\n return useContext(HotkeysContext)\n}\n\ninterface Props {\n initiallyActiveScopes?: string[]\n children: ReactNode\n}\n\nexport const HotkeysProvider = ({ initiallyActiveScopes = ['*'], children }: Props) => {\n const [internalActiveScopes, setInternalActiveScopes] = useState(initiallyActiveScopes)\n const [boundHotkeys, setBoundHotkeys] = useState<Hotkey[]>([])\n\n const enableScope = useCallback((scope: string) => {\n setInternalActiveScopes((prev) => {\n if (prev.includes('*')) {\n return [scope]\n }\n return Array.from(new Set([...prev, scope]))\n })\n }, [])\n\n const disableScope = useCallback((scope: string) => {\n setInternalActiveScopes((prev) => {\n return prev.filter((s) => s !== scope)\n })\n }, [])\n\n const toggleScope = useCallback((scope: string) => {\n setInternalActiveScopes((prev) => {\n if (prev.includes(scope)) {\n return prev.filter((s) => s !== scope)\n } else {\n if (prev.includes('*')) {\n return [scope]\n }\n return Array.from(new Set([...prev, scope]))\n }\n })\n }, [])\n\n const addBoundHotkey = useCallback((hotkey: Hotkey) => {\n setBoundHotkeys((prev) => [...prev, hotkey])\n }, [])\n\n const removeBoundHotkey = useCallback((hotkey: Hotkey) => {\n setBoundHotkeys((prev) => prev.filter((h) => !deepEqual(h, hotkey)))\n }, [])\n\n return (\n <HotkeysContext.Provider\n value={{ activeScopes: internalActiveScopes, hotkeys: boundHotkeys, enableScope, disableScope, toggleScope }}\n >\n <BoundHotkeysProxyProviderProvider addHotkey={addBoundHotkey} removeHotkey={removeBoundHotkey}>\n {children}\n </BoundHotkeysProxyProviderProvider>\n </HotkeysContext.Provider>\n )\n}\n","import { useRef } from 'react'\nimport deepEqual from './deepEqual'\n\nexport default function useDeepEqualMemo<T>(value: T) {\n const ref = useRef<T | undefined>(undefined)\n\n if (!deepEqual(ref.current, value)) {\n ref.current = value\n }\n\n return ref.current\n}\n","import { HotkeyCallback, Keys, Options, OptionsOrDependencyArray, RefType } from './types'\nimport { DependencyList, useCallback, useEffect, useLayoutEffect, useRef } from 'react'\nimport { mapKey, parseHotkey, parseKeysHookInput } from './parseHotkeys'\nimport {\n isHotkeyEnabled,\n isHotkeyEnabledOnTag,\n isHotkeyMatchingKeyboardEvent,\n isKeyboardEventTriggeredByInput,\n isScopeActive,\n maybePreventDefault,\n} from './validators'\nimport { useHotkeysContext } from './HotkeysProvider'\nimport { useBoundHotkeysProxy } from './BoundHotkeysProxyProvider'\nimport useDeepEqualMemo from './useDeepEqualMemo'\nimport { isReadonlyArray, pushToCurrentlyPressedKeys, removeFromCurrentlyPressedKeys } from './isHotkeyPressed'\n\nconst stopPropagation = (e: KeyboardEvent): void => {\n e.stopPropagation()\n e.preventDefault()\n e.stopImmediatePropagation()\n}\n\nconst useSafeLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect\n\nexport default function useHotkeys<T extends HTMLElement>(\n keys: Keys,\n callback: HotkeyCallback,\n options?: OptionsOrDependencyArray,\n dependencies?: OptionsOrDependencyArray\n) {\n const ref = useRef<RefType<T>>(null)\n const hasTriggeredRef = useRef(false)\n\n const _options: Options | undefined = !(options instanceof Array)\n ? (options as Options)\n : !(dependencies instanceof Array)\n ? (dependencies as Options)\n : undefined\n const _keys: string = isReadonlyArray(keys) ? keys.join(_options?.splitKey) : keys\n const _deps: DependencyList | undefined =\n options instanceof Array ? options : dependencies instanceof Array ? dependencies : undefined\n\n const memoisedCB = useCallback(callback, _deps ?? [])\n const cbRef = useRef<HotkeyCallback>(memoisedCB)\n\n if (_deps) {\n cbRef.current = memoisedCB\n } else {\n cbRef.current = callback\n }\n\n const memoisedOptions = useDeepEqualMemo(_options)\n\n const { activeScopes } = useHotkeysContext()\n const proxy = useBoundHotkeysProxy()\n\n useSafeLayoutEffect(() => {\n if (memoisedOptions?.enabled === false || !isScopeActive(activeScopes, memoisedOptions?.scopes)) {\n return\n }\n\n const listener = (e: KeyboardEvent, isKeyUp = false) => {\n if (isKeyboardEventTriggeredByInput(e) && !isHotkeyEnabledOnTag(e, memoisedOptions?.enableOnFormTags)) {\n return\n }\n\n // TODO: SINCE THE EVENT IS NOW ATTACHED TO THE REF, THE ACTIVE ELEMENT CAN NEVER BE INSIDE THE REF. THE HOTKEY ONLY TRIGGERS IF THE\n // REF IS THE ACTIVE ELEMENT. THIS IS A PROBLEM SINCE FOCUSED SUB COMPONENTS WON'T TRIGGER THE HOTKEY.\n if (ref.current !== null) {\n const rootNode = ref.current.getRootNode()\n\n if (\n (rootNode instanceof Document || rootNode instanceof ShadowRoot) &&\n rootNode.activeElement !== ref.current &&\n !ref.current.contains(rootNode.activeElement)\n ) {\n stopPropagation(e)\n return\n }\n }\n\n if ((e.target as HTMLElement)?.isContentEditable && !memoisedOptions?.enableOnContentEditable) {\n return\n }\n\n parseKeysHookInput(_keys, memoisedOptions?.splitKey).forEach((key) => {\n const hotkey = parseHotkey(key, memoisedOptions?.combinationKey)\n\n if (isHotkeyMatchingKeyboardEvent(e, hotkey, memoisedOptions?.ignoreModifiers) || hotkey.keys?.includes('*')) {\n if (memoisedOptions?.ignoreEventWhen?.(e)) {\n return\n }\n\n if (isKeyUp && hasTriggeredRef.current) {\n return\n }\n\n maybePreventDefault(e, hotkey, memoisedOptions?.preventDefault)\n\n if (!isHotkeyEnabled(e, hotkey, memoisedOptions?.enabled)) {\n stopPropagation(e)\n\n return\n }\n\n // Execute the user callback for that hotkey\n cbRef.current(e, hotkey)\n\n if (!isKeyUp) {\n hasTriggeredRef.current = true\n }\n }\n })\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === undefined) {\n // Synthetic event (e.g., Chrome autofill). Ignore.\n return\n }\n\n pushToCurrentlyPressedKeys(mapKey(event.key))\n\n if ((memoisedOptions?.keydown === undefined && memoisedOptions?.keyup !== true) || memoisedOptions?.keydown) {\n listener(event)\n }\n }\n\n const handleKeyUp = (event: KeyboardEvent) => {\n if (event.key === undefined) {\n // Synthetic event (e.g., Chrome autofill). Ignore.\n return\n }\n\n removeFromCurrentlyPressedKeys(mapKey(event.key))\n\n hasTriggeredRef.current = false\n\n if (memoisedOptions?.keyup) {\n listener(event, true)\n }\n }\n\n const domNode = ref.current || _options?.document || document\n\n // @ts-ignore\n domNode.addEventListener('keyup', handleKeyUp)\n // @ts-ignore\n domNode.addEventListener('keydown', handleKeyDown)\n\n if (proxy) {\n parseKeysHookInput(_keys, memoisedOptions?.splitKey).forEach((key) =>\n proxy.addHotkey(parseHotkey(key, memoisedOptions?.combinationKey, memoisedOptions?.description))\n )\n }\n\n return () => {\n // @ts-ignore\n domNode.removeEventListener('keyup', handleKeyUp)\n // @ts-ignore\n domNode.removeEventListener('keydown', handleKeyDown)\n\n if (proxy) {\n parseKeysHookInput(_keys, memoisedOptions?.splitKey).forEach((key) =>\n proxy.removeHotkey(parseHotkey(key, memoisedOptions?.combinationKey, memoisedOptions?.description))\n )\n }\n }\n }, [_keys, memoisedOptions, activeScopes])\n\n return ref\n}\n","import { useCallback, useState } from 'react'\nimport { mapKey } from './parseHotkeys'\n\nexport default function useRecordHotkeys() {\n const [keys, setKeys] = useState(new Set<string>())\n const [isRecording, setIsRecording] = useState(false)\n\n const handler = useCallback((event: KeyboardEvent) => {\n if (event.key === undefined) {\n // Synthetic event (e.g., Chrome autofill). Ignore.\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n\n setKeys((prev) => {\n const newKeys = new Set(prev)\n\n newKeys.add(mapKey(event.key))\n\n return newKeys\n })\n }, [])\n\n const stop = useCallback(() => {\n if (typeof document !== 'undefined') {\n document.removeEventListener('keydown', handler)\n\n setIsRecording(false)\n }\n }, [handler])\n\n const start = useCallback(() => {\n setKeys(new Set<string>())\n\n if (typeof document !== 'undefined') {\n stop()\n\n document.addEventListener('keydown', handler)\n\n setIsRecording(true)\n }\n }, [handler, stop])\n\n return [keys, { start, stop, isRecording }] as const\n}\n"],"names":["reservedModifierKeywords","mappedKeys","esc","left","right","up","down","space","ShiftLeft","ShiftRight","AltLeft","AltRight","MetaLeft","MetaRight","OSLeft","OSRight","ControlLeft","ControlRight","mapKey","key","trim","toLowerCase","replace","isHotkeyModifier","includes","parseKeysHookInput","keys","splitKey","split","parseHotkey","hotkey","combinationKey","description","toLocaleLowerCase","map","k","modifiers","alt","ctrl","shift","meta","mod","singleCharKeys","filter","_extends","document","addEventListener","e","undefined","console","log","length","pushToCurrentlyPressedKeys","removeFromCurrentlyPressedKeys","window","currentlyPressedKeys","clear","Set","isReadonlyArray","value","Array","isArray","isHotkeyPressed","hotkeyArray","every","has","forEach","add","maybePreventDefault","preventDefault","isHotkeyEnabled","enabled","isKeyboardEventTriggeredByInput","ev","isHotkeyEnabledOnTag","_ref","enabledOnTags","target","targetTagName","tagName","Boolean","some","tag","isScopeActive","activeScopes","scopes","warn","scope","isHotkeyMatchingKeyboardEvent","ignoreModifiers","pressedKeyUppercase","ctrlKey","metaKey","shiftKey","altKey","pressedKey","BoundHotkeysProxyProvider","createContext","useBoundHotkeysProxy","useContext","BoundHotkeysProxyProviderProvider","addHotkey","removeHotkey","children","_jsx","Provider","deepEqual","x","y","Object","reduce","isEqual","HotkeysContext","hotkeys","toggleScope","enableScope","disableScope","useHotkeysContext","HotkeysProvider","initiallyActiveScopes","_ref$initiallyActiveS","_useState","useState","internalActiveScopes","setInternalActiveScopes","_useState2","boundHotkeys","setBoundHotkeys","useCallback","prev","from","concat","s","addBoundHotkey","removeBoundHotkey","h","useDeepEqualMemo","ref","useRef","current","stopPropagation","stopImmediatePropagation","useSafeLayoutEffect","useLayoutEffect","useEffect","useHotkeys","callback","options","dependencies","hasTriggeredRef","_options","_keys","join","_deps","memoisedCB","cbRef","memoisedOptions","_useHotkeysContext","proxy","listener","isKeyUp","enableOnFormTags","rootNode","getRootNode","Document","ShadowRoot","activeElement","contains","_e$target","isContentEditable","enableOnContentEditable","_hotkey$keys","ignoreEventWhen","handleKeyDown","event","keydown","keyup","handleKeyUp","domNode","removeEventListener","useRecordHotkeys","setKeys","isRecording","setIsRecording","handler","newKeys","stop","start"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -0,0 +1,36 @@
1
+ import type { DependencyList } from 'react';
2
+ export declare type FormTags = 'input' | 'textarea' | 'select' | 'INPUT' | 'TEXTAREA' | 'SELECT';
3
+ export declare type Keys = string | readonly string[];
4
+ export declare type Scopes = string | readonly string[];
5
+ export declare type RefType<T> = T | null;
6
+ export declare type KeyboardModifiers = {
7
+ alt?: boolean;
8
+ ctrl?: boolean;
9
+ meta?: boolean;
10
+ shift?: boolean;
11
+ mod?: boolean;
12
+ };
13
+ export declare type Hotkey = KeyboardModifiers & {
14
+ keys?: readonly string[];
15
+ scopes?: Scopes;
16
+ description?: string;
17
+ };
18
+ export declare type HotkeysEvent = Hotkey;
19
+ export declare type HotkeyCallback = (keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => void;
20
+ export declare type Trigger = boolean | ((keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => boolean);
21
+ export declare type Options = {
22
+ enabled?: Trigger;
23
+ enableOnFormTags?: readonly FormTags[] | boolean;
24
+ enableOnContentEditable?: boolean;
25
+ ignoreEventWhen?: (e: KeyboardEvent) => boolean;
26
+ combinationKey?: string;
27
+ splitKey?: string;
28
+ scopes?: Scopes;
29
+ keyup?: boolean;
30
+ keydown?: boolean;
31
+ preventDefault?: Trigger;
32
+ description?: string;
33
+ document?: Document;
34
+ ignoreModifiers?: boolean;
35
+ };
36
+ export declare type OptionsOrDependencyArray = Options | DependencyList;
@@ -0,0 +1 @@
1
+ export default function useDeepEqualMemo<T>(value: T): T | undefined;
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import { HotkeyCallback, Keys, OptionsOrDependencyArray, RefType } from './types';
3
+ export default function useHotkeys<T extends HTMLElement>(keys: Keys, callback: HotkeyCallback, options?: OptionsOrDependencyArray, dependencies?: OptionsOrDependencyArray): import("react").MutableRefObject<RefType<T>>;
@@ -0,0 +1,5 @@
1
+ export default function useRecordHotkeys(): readonly [Set<string>, {
2
+ readonly start: () => void;
3
+ readonly stop: () => void;
4
+ readonly isRecording: boolean;
5
+ }];
@@ -0,0 +1,7 @@
1
+ import { FormTags, Hotkey, Scopes, Trigger } from './types';
2
+ export declare function maybePreventDefault(e: KeyboardEvent, hotkey: Hotkey, preventDefault?: Trigger): void;
3
+ export declare function isHotkeyEnabled(e: KeyboardEvent, hotkey: Hotkey, enabled?: Trigger): boolean;
4
+ export declare function isKeyboardEventTriggeredByInput(ev: KeyboardEvent): boolean;
5
+ export declare function isHotkeyEnabledOnTag({ target }: KeyboardEvent, enabledOnTags?: readonly FormTags[] | boolean): boolean;
6
+ export declare function isScopeActive(activeScopes: string[], scopes?: Scopes): boolean;
7
+ export declare const isHotkeyMatchingKeyboardEvent: (e: KeyboardEvent, hotkey: Hotkey, ignoreModifiers?: boolean) => boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-hotkeys-hook",
3
3
  "description": "React hook for handling keyboard shortcuts",
4
- "version": "4.4.2",
4
+ "version": "5.0.0-0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/JohannesKlauss/react-keymap-hook.git"
@@ -78,18 +78,18 @@
78
78
  }
79
79
  },
80
80
  "devDependencies": {
81
- "@babel/core": "7.23.2",
81
+ "@babel/core": "7.23.7",
82
82
  "@babel/plugin-proposal-class-properties": "7.18.6",
83
- "@babel/plugin-transform-react-jsx": "7.22.15",
84
- "@babel/preset-env": "7.23.2",
85
- "@babel/preset-react": "7.22.15",
86
- "@babel/preset-typescript": "7.23.2",
83
+ "@babel/plugin-transform-react-jsx": "7.23.4",
84
+ "@babel/preset-env": "7.23.7",
85
+ "@babel/preset-react": "7.23.3",
86
+ "@babel/preset-typescript": "7.23.3",
87
87
  "@testing-library/jest-dom": "5.17.0",
88
- "@testing-library/react": "14.0.0",
89
- "@testing-library/user-event": "14.4.3",
90
- "@types/jest": "29.5.6",
91
- "@types/react": "18.2.33",
92
- "@types/react-dom": "18.2.14",
88
+ "@testing-library/react": "14.1.2",
89
+ "@testing-library/user-event": "14.5.2",
90
+ "@types/jest": "29.5.11",
91
+ "@types/react": "18.2.46",
92
+ "@types/react-dom": "18.2.18",
93
93
  "@typescript-eslint/eslint-plugin": "5.60.0",
94
94
  "@typescript-eslint/parser": "5.60.0",
95
95
  "eslint": "8.56.0",
@@ -102,8 +102,8 @@
102
102
  "react-dom": "18.2.0",
103
103
  "react-test-renderer": "18.2.0",
104
104
  "tsdx": "0.14.1",
105
- "tslib": "2.5.3",
106
- "typescript": "5.0.4"
105
+ "tslib": "2.6.2",
106
+ "typescript": "5.3.3"
107
107
  },
108
108
  "peerDependencies": {
109
109
  "react": ">=16.8.1",
@@ -5,7 +5,7 @@ import deepEqual from './deepEqual'
5
5
 
6
6
  export type HotkeysContextType = {
7
7
  hotkeys: ReadonlyArray<Hotkey>
8
- enabledScopes: string[]
8
+ activeScopes: string[]
9
9
  toggleScope: (scope: string) => void
10
10
  enableScope: (scope: string) => void
11
11
  disableScope: (scope: string) => void
@@ -14,7 +14,7 @@ export type HotkeysContextType = {
14
14
  // The context is only needed for special features like global scoping, so we use a graceful default fallback
15
15
  const HotkeysContext = createContext<HotkeysContextType>({
16
16
  hotkeys: [],
17
- enabledScopes: [], // This array has to be empty instead of containing '*' as default, to check if the provider is set or not
17
+ activeScopes: [], // This array has to be empty instead of containing '*' as default, to check if the provider is set or not
18
18
  toggleScope: () => {},
19
19
  enableScope: () => {},
20
20
  disableScope: () => {},
@@ -30,9 +30,7 @@ interface Props {
30
30
  }
31
31
 
32
32
  export const HotkeysProvider = ({ initiallyActiveScopes = ['*'], children }: Props) => {
33
- const [internalActiveScopes, setInternalActiveScopes] = useState(
34
- initiallyActiveScopes?.length > 0 ? initiallyActiveScopes : ['*']
35
- )
33
+ const [internalActiveScopes, setInternalActiveScopes] = useState(initiallyActiveScopes)
36
34
  const [boundHotkeys, setBoundHotkeys] = useState<Hotkey[]>([])
37
35
 
38
36
  const enableScope = useCallback((scope: string) => {
@@ -40,34 +38,24 @@ export const HotkeysProvider = ({ initiallyActiveScopes = ['*'], children }: Pro
40
38
  if (prev.includes('*')) {
41
39
  return [scope]
42
40
  }
43
-
44
41
  return Array.from(new Set([...prev, scope]))
45
42
  })
46
43
  }, [])
47
44
 
48
45
  const disableScope = useCallback((scope: string) => {
49
46
  setInternalActiveScopes((prev) => {
50
- if (prev.filter((s) => s !== scope).length === 0) {
51
- return ['*']
52
- } else {
53
- return prev.filter((s) => s !== scope)
54
- }
47
+ return prev.filter((s) => s !== scope)
55
48
  })
56
49
  }, [])
57
50
 
58
51
  const toggleScope = useCallback((scope: string) => {
59
52
  setInternalActiveScopes((prev) => {
60
53
  if (prev.includes(scope)) {
61
- if (prev.filter((s) => s !== scope).length === 0) {
62
- return ['*']
63
- } else {
64
- return prev.filter((s) => s !== scope)
65
- }
54
+ return prev.filter((s) => s !== scope)
66
55
  } else {
67
56
  if (prev.includes('*')) {
68
57
  return [scope]
69
58
  }
70
-
71
59
  return Array.from(new Set([...prev, scope]))
72
60
  }
73
61
  })
@@ -83,7 +71,7 @@ export const HotkeysProvider = ({ initiallyActiveScopes = ['*'], children }: Pro
83
71
 
84
72
  return (
85
73
  <HotkeysContext.Provider
86
- value={{ enabledScopes: internalActiveScopes, hotkeys: boundHotkeys, enableScope, disableScope, toggleScope }}
74
+ value={{ activeScopes: internalActiveScopes, hotkeys: boundHotkeys, enableScope, disableScope, toggleScope }}
87
75
  >
88
76
  <BoundHotkeysProxyProviderProvider addHotkey={addBoundHotkey} removeHotkey={removeBoundHotkey}>
89
77
  {children}
@@ -3,20 +3,22 @@ import { isHotkeyModifier, mapKey } from './parseHotkeys'
3
3
  if (typeof document !== 'undefined') {
4
4
  document.addEventListener('keydown', (e) => {
5
5
  if (e.key === undefined) {
6
- // Synthetic event (e.g., Chrome autofill). Ignore.
6
+ // Synthetic event (e.g., Chrome autofill). Ignore.
7
7
  return
8
8
  }
9
9
 
10
- pushToCurrentlyPressedKeys([mapKey(e.key), mapKey(e.code)])
10
+ console.log('keydown', e.key, mapKey(e.key), e.key.length)
11
+
12
+ pushToCurrentlyPressedKeys([mapKey(e.key)])
11
13
  })
12
14
 
13
15
  document.addEventListener('keyup', (e) => {
14
16
  if (e.key === undefined) {
15
- // Synthetic event (e.g., Chrome autofill). Ignore.
17
+ // Synthetic event (e.g., Chrome autofill). Ignore.
16
18
  return
17
19
  }
18
20
 
19
- removeFromCurrentlyPressedKeys([mapKey(e.key), mapKey(e.code)])
21
+ removeFromCurrentlyPressedKeys([mapKey(e.key)])
20
22
  })
21
23
  }
22
24
 
@@ -5,13 +5,11 @@ const reservedModifierKeywords = ['shift', 'alt', 'meta', 'mod', 'ctrl']
5
5
  const mappedKeys: Record<string, string> = {
6
6
  esc: 'escape',
7
7
  return: 'enter',
8
- '.': 'period',
9
- ',': 'comma',
10
- '-': 'slash',
11
- ' ': 'space',
12
- '`': 'backquote',
13
- '#': 'backslash',
14
- '+': 'bracketright',
8
+ left: 'arrowleft',
9
+ right: 'arrowright',
10
+ up: 'arrowup',
11
+ down: 'arrowdown',
12
+ space: ' ',
15
13
  ShiftLeft: 'shift',
16
14
  ShiftRight: 'shift',
17
15
  AltLeft: 'alt',
@@ -25,10 +23,7 @@ const mappedKeys: Record<string, string> = {
25
23
  }
26
24
 
27
25
  export function mapKey(key: string): string {
28
- return (mappedKeys[key] || key)
29
- .trim()
30
- .toLowerCase()
31
- .replace(/key|digit|numpad|arrow/, '')
26
+ return (mappedKeys[key.trim()] || key.trim()).toLowerCase().replace(/key|digit|numpad/, '')
32
27
  }
33
28
 
34
29
  export function isHotkeyModifier(key: string) {
package/src/useHotkeys.ts CHANGED
@@ -51,11 +51,11 @@ export default function useHotkeys<T extends HTMLElement>(
51
51
 
52
52
  const memoisedOptions = useDeepEqualMemo(_options)
53
53
 
54
- const { enabledScopes } = useHotkeysContext()
54
+ const { activeScopes } = useHotkeysContext()
55
55
  const proxy = useBoundHotkeysProxy()
56
56
 
57
57
  useSafeLayoutEffect(() => {
58
- if (memoisedOptions?.enabled === false || !isScopeActive(enabledScopes, memoisedOptions?.scopes)) {
58
+ if (memoisedOptions?.enabled === false || !isScopeActive(activeScopes, memoisedOptions?.scopes)) {
59
59
  return
60
60
  }
61
61
 
@@ -64,20 +64,19 @@ export default function useHotkeys<T extends HTMLElement>(
64
64
  return
65
65
  }
66
66
 
67
- if (memoisedOptions?.ignoreEventWhen?.(e)) {
68
- return
69
- }
70
-
71
67
  // TODO: SINCE THE EVENT IS NOW ATTACHED TO THE REF, THE ACTIVE ELEMENT CAN NEVER BE INSIDE THE REF. THE HOTKEY ONLY TRIGGERS IF THE
72
68
  // REF IS THE ACTIVE ELEMENT. THIS IS A PROBLEM SINCE FOCUSED SUB COMPONENTS WON'T TRIGGER THE HOTKEY.
73
- if (
74
- ref.current !== null &&
75
- document.activeElement !== ref.current &&
76
- !ref.current.contains(document.activeElement)
77
- ) {
78
- stopPropagation(e)
79
-
80
- return
69
+ if (ref.current !== null) {
70
+ const rootNode = ref.current.getRootNode()
71
+
72
+ if (
73
+ (rootNode instanceof Document || rootNode instanceof ShadowRoot) &&
74
+ rootNode.activeElement !== ref.current &&
75
+ !ref.current.contains(rootNode.activeElement)
76
+ ) {
77
+ stopPropagation(e)
78
+ return
79
+ }
81
80
  }
82
81
 
83
82
  if ((e.target as HTMLElement)?.isContentEditable && !memoisedOptions?.enableOnContentEditable) {
@@ -88,6 +87,10 @@ export default function useHotkeys<T extends HTMLElement>(
88
87
  const hotkey = parseHotkey(key, memoisedOptions?.combinationKey)
89
88
 
90
89
  if (isHotkeyMatchingKeyboardEvent(e, hotkey, memoisedOptions?.ignoreModifiers) || hotkey.keys?.includes('*')) {
90
+ if (memoisedOptions?.ignoreEventWhen?.(e)) {
91
+ return
92
+ }
93
+
91
94
  if (isKeyUp && hasTriggeredRef.current) {
92
95
  return
93
96
  }
@@ -116,7 +119,7 @@ export default function useHotkeys<T extends HTMLElement>(
116
119
  return
117
120
  }
118
121
 
119
- pushToCurrentlyPressedKeys(mapKey(event.code))
122
+ pushToCurrentlyPressedKeys(mapKey(event.key))
120
123
 
121
124
  if ((memoisedOptions?.keydown === undefined && memoisedOptions?.keyup !== true) || memoisedOptions?.keydown) {
122
125
  listener(event)
@@ -129,7 +132,7 @@ export default function useHotkeys<T extends HTMLElement>(
129
132
  return
130
133
  }
131
134
 
132
- removeFromCurrentlyPressedKeys(mapKey(event.code))
135
+ removeFromCurrentlyPressedKeys(mapKey(event.key))
133
136
 
134
137
  hasTriggeredRef.current = false
135
138
 
@@ -163,7 +166,7 @@ export default function useHotkeys<T extends HTMLElement>(
163
166
  )
164
167
  }
165
168
  }
166
- }, [_keys, memoisedOptions, enabledScopes])
169
+ }, [_keys, memoisedOptions, activeScopes])
167
170
 
168
171
  return ref
169
172
  }
@@ -17,7 +17,7 @@ export default function useRecordHotkeys() {
17
17
  setKeys((prev) => {
18
18
  const newKeys = new Set(prev)
19
19
 
20
- newKeys.add(mapKey(event.code))
20
+ newKeys.add(mapKey(event.key))
21
21
 
22
22
  return newKeys
23
23
  })
package/src/validators.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { FormTags, Hotkey, Scopes, Trigger } from './types'
2
2
  import { isHotkeyPressed, isReadonlyArray } from './isHotkeyPressed'
3
- import { mapKey } from './parseHotkeys'
4
3
 
5
4
  export function maybePreventDefault(e: KeyboardEvent, hotkey: Hotkey, preventDefault?: Trigger): void {
6
5
  if ((typeof preventDefault === 'function' && preventDefault(e, hotkey)) || preventDefault === true) {
@@ -53,13 +52,15 @@ export function isScopeActive(activeScopes: string[], scopes?: Scopes): boolean
53
52
 
54
53
  export const isHotkeyMatchingKeyboardEvent = (e: KeyboardEvent, hotkey: Hotkey, ignoreModifiers = false): boolean => {
55
54
  const { alt, meta, mod, shift, ctrl, keys } = hotkey
56
- const { key: pressedKeyUppercase, code, ctrlKey, metaKey, shiftKey, altKey } = e
55
+ const { key: pressedKeyUppercase, ctrlKey, metaKey, shiftKey, altKey } = e
57
56
 
58
- const keyCode = mapKey(code)
59
57
  const pressedKey = pressedKeyUppercase.toLowerCase()
60
58
 
61
- if (!keys?.includes(keyCode) && !['ctrl', 'control', 'unknown', 'meta', 'alt', 'shift', 'os'].includes(keyCode)) {
62
- return false;
59
+ if (
60
+ !keys?.includes(pressedKey) &&
61
+ !['ctrl', 'control', 'unknown', 'meta', 'alt', 'shift', 'os'].includes(pressedKey)
62
+ ) {
63
+ return false
63
64
  }
64
65
 
65
66
  if (!ignoreModifiers) {
@@ -90,7 +91,7 @@ export const isHotkeyMatchingKeyboardEvent = (e: KeyboardEvent, hotkey: Hotkey,
90
91
 
91
92
  // All modifiers are correct, now check the key
92
93
  // If the key is set, we check for the key
93
- if (keys && keys.length === 1 && (keys.includes(pressedKey) || keys.includes(keyCode))) {
94
+ if (keys && keys.length === 1 && keys.includes(pressedKey)) {
94
95
  return true
95
96
  } else if (keys) {
96
97
  // Check if all keys are present in pressedDownKeys set