react-hotkeys-hook 4.3.5 → 4.3.6-1
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.
- package/dist/index.d.ts +1 -1
- package/dist/react-hotkeys-hook.cjs.development.js +44 -38
- package/dist/react-hotkeys-hook.cjs.development.js.map +1 -1
- package/dist/react-hotkeys-hook.cjs.production.min.js +1 -1
- package/dist/react-hotkeys-hook.cjs.production.min.js.map +1 -1
- package/dist/react-hotkeys-hook.esm.js +44 -38
- package/dist/react-hotkeys-hook.esm.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +45 -8
- package/src/BoundHotkeysProxyProvider.tsx +7 -3
- package/src/HotkeysProvider.tsx +13 -9
- package/src/deepEqual.ts +5 -6
- package/src/index.ts +1 -8
- package/src/isHotkeyPressed.ts +31 -32
- package/src/parseHotkeys.ts +20 -15
- package/src/types.ts +1 -1
- package/src/useHotkeys.ts +31 -16
- package/src/useRecordHotkeys.ts +2 -2
- package/src/validators.ts +6 -4
package/src/parseHotkeys.ts
CHANGED
|
@@ -12,31 +12,34 @@ const mappedKeys: Record<string, string> = {
|
|
|
12
12
|
'`': 'backquote',
|
|
13
13
|
'#': 'backslash',
|
|
14
14
|
'+': 'bracketright',
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
ShiftLeft: 'shift',
|
|
16
|
+
ShiftRight: 'shift',
|
|
17
|
+
AltLeft: 'alt',
|
|
18
|
+
AltRight: 'alt',
|
|
19
|
+
MetaLeft: 'meta',
|
|
20
|
+
MetaRight: 'meta',
|
|
21
|
+
OSLeft: 'meta',
|
|
22
|
+
OSRight: 'meta',
|
|
23
|
+
ControlLeft: 'ctrl',
|
|
24
|
+
ControlRight: 'ctrl',
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export function mapKey(key: string): string {
|
|
28
|
+
console.log('key', key)
|
|
29
|
+
|
|
30
|
+
console.log('mappedKeys[key]', mappedKeys[key])
|
|
31
|
+
|
|
26
32
|
return (mappedKeys[key] || key)
|
|
27
33
|
.trim()
|
|
28
34
|
.toLowerCase()
|
|
29
|
-
.replace(
|
|
30
|
-
.replace('digit', '')
|
|
31
|
-
.replace('numpad', '')
|
|
32
|
-
.replace('arrow', '')
|
|
35
|
+
.replace(/key|digit|numpad|arrow/, '')
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
export function isHotkeyModifier(key: string) {
|
|
36
39
|
return reservedModifierKeywords.includes(key)
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
export function parseKeysHookInput(keys: Keys, splitKey
|
|
42
|
+
export function parseKeysHookInput(keys: Keys, splitKey = ','): string[] {
|
|
40
43
|
if (typeof keys === 'string') {
|
|
41
44
|
return keys.split(splitKey)
|
|
42
45
|
}
|
|
@@ -44,11 +47,13 @@ export function parseKeysHookInput(keys: Keys, splitKey: string = ','): string[]
|
|
|
44
47
|
return keys
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
export function parseHotkey(hotkey: string, combinationKey
|
|
50
|
+
export function parseHotkey(hotkey: string, combinationKey = '+'): Hotkey {
|
|
48
51
|
const keys = hotkey
|
|
49
52
|
.toLocaleLowerCase()
|
|
50
53
|
.split(combinationKey)
|
|
51
|
-
.map(k => mapKey(k))
|
|
54
|
+
.map((k) => mapKey(k))
|
|
55
|
+
|
|
56
|
+
console.log('parsed keys', keys)
|
|
52
57
|
|
|
53
58
|
const modifiers: KeyboardModifiers = {
|
|
54
59
|
alt: keys.includes('alt'),
|
package/src/types.ts
CHANGED
package/src/useHotkeys.ts
CHANGED
|
@@ -26,21 +26,26 @@ export default function useHotkeys<T extends HTMLElement>(
|
|
|
26
26
|
keys: Keys,
|
|
27
27
|
callback: HotkeyCallback,
|
|
28
28
|
options?: OptionsOrDependencyArray,
|
|
29
|
-
dependencies?: OptionsOrDependencyArray
|
|
29
|
+
dependencies?: OptionsOrDependencyArray
|
|
30
30
|
) {
|
|
31
31
|
const ref = useRef<RefType<T>>(null)
|
|
32
32
|
const hasTriggeredRef = useRef(false)
|
|
33
33
|
|
|
34
|
-
const _options: Options | undefined = !(options instanceof Array)
|
|
35
|
-
|
|
34
|
+
const _options: Options | undefined = !(options instanceof Array)
|
|
35
|
+
? (options as Options)
|
|
36
|
+
: !(dependencies instanceof Array)
|
|
37
|
+
? (dependencies as Options)
|
|
38
|
+
: undefined
|
|
39
|
+
const _deps: DependencyList | undefined =
|
|
40
|
+
options instanceof Array ? options : dependencies instanceof Array ? dependencies : undefined
|
|
36
41
|
|
|
37
42
|
const memoisedCB = useCallback(callback, _deps ?? [])
|
|
38
|
-
const cbRef = useRef<HotkeyCallback>(memoisedCB)
|
|
43
|
+
const cbRef = useRef<HotkeyCallback>(memoisedCB)
|
|
39
44
|
|
|
40
|
-
if(_deps) {
|
|
41
|
-
cbRef.current = memoisedCB
|
|
45
|
+
if (_deps) {
|
|
46
|
+
cbRef.current = memoisedCB
|
|
42
47
|
} else {
|
|
43
|
-
cbRef.current = callback
|
|
48
|
+
cbRef.current = callback
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
const memoisedOptions = useDeepEqualMemo(_options)
|
|
@@ -53,20 +58,24 @@ export default function useHotkeys<T extends HTMLElement>(
|
|
|
53
58
|
return
|
|
54
59
|
}
|
|
55
60
|
|
|
56
|
-
const listener = (e: KeyboardEvent, isKeyUp
|
|
61
|
+
const listener = (e: KeyboardEvent, isKeyUp = false) => {
|
|
57
62
|
if (isKeyboardEventTriggeredByInput(e) && !isHotkeyEnabledOnTag(e, memoisedOptions?.enableOnFormTags)) {
|
|
58
63
|
return
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
// 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
|
|
62
67
|
// REF IS THE ACTIVE ELEMENT. THIS IS A PROBLEM SINCE FOCUSED SUB COMPONENTS WON'T TRIGGER THE HOTKEY.
|
|
63
|
-
if (
|
|
68
|
+
if (
|
|
69
|
+
ref.current !== null &&
|
|
70
|
+
document.activeElement !== ref.current &&
|
|
71
|
+
!ref.current.contains(document.activeElement)
|
|
72
|
+
) {
|
|
64
73
|
stopPropagation(e)
|
|
65
74
|
|
|
66
75
|
return
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
if ((
|
|
78
|
+
if ((e.target as HTMLElement)?.isContentEditable && !memoisedOptions?.enableOnContentEditable) {
|
|
70
79
|
return
|
|
71
80
|
}
|
|
72
81
|
|
|
@@ -124,23 +133,29 @@ export default function useHotkeys<T extends HTMLElement>(
|
|
|
124
133
|
}
|
|
125
134
|
}
|
|
126
135
|
|
|
136
|
+
const domNode = ref.current || _options?.document || document
|
|
137
|
+
|
|
127
138
|
// @ts-ignore
|
|
128
|
-
|
|
139
|
+
domNode.addEventListener('keyup', handleKeyUp)
|
|
129
140
|
// @ts-ignore
|
|
130
|
-
|
|
141
|
+
domNode.addEventListener('keydown', handleKeyDown)
|
|
131
142
|
|
|
132
143
|
if (proxy) {
|
|
133
|
-
parseKeysHookInput(keys, memoisedOptions?.splitKey).forEach((key) =>
|
|
144
|
+
parseKeysHookInput(keys, memoisedOptions?.splitKey).forEach((key) =>
|
|
145
|
+
proxy.addHotkey(parseHotkey(key, memoisedOptions?.combinationKey))
|
|
146
|
+
)
|
|
134
147
|
}
|
|
135
148
|
|
|
136
149
|
return () => {
|
|
137
150
|
// @ts-ignore
|
|
138
|
-
|
|
151
|
+
domNode.removeEventListener('keyup', handleKeyUp)
|
|
139
152
|
// @ts-ignore
|
|
140
|
-
|
|
153
|
+
domNode.removeEventListener('keydown', handleKeyDown)
|
|
141
154
|
|
|
142
155
|
if (proxy) {
|
|
143
|
-
parseKeysHookInput(keys, memoisedOptions?.splitKey).forEach((key) =>
|
|
156
|
+
parseKeysHookInput(keys, memoisedOptions?.splitKey).forEach((key) =>
|
|
157
|
+
proxy.removeHotkey(parseHotkey(key, memoisedOptions?.combinationKey))
|
|
158
|
+
)
|
|
144
159
|
}
|
|
145
160
|
}
|
|
146
161
|
}, [keys, memoisedOptions, enabledScopes])
|
package/src/useRecordHotkeys.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { mapKey } from './parseHotkeys'
|
|
|
3
3
|
|
|
4
4
|
export default function useRecordHotkeys() {
|
|
5
5
|
const [keys, setKeys] = useState(new Set<string>())
|
|
6
|
-
const [isRecording, setIsRecording] = useState(false)
|
|
6
|
+
const [isRecording, setIsRecording] = useState(false)
|
|
7
7
|
|
|
8
8
|
const handler = useCallback((event: KeyboardEvent) => {
|
|
9
9
|
if (event.key === undefined) {
|
|
@@ -14,7 +14,7 @@ export default function useRecordHotkeys() {
|
|
|
14
14
|
event.preventDefault()
|
|
15
15
|
event.stopPropagation()
|
|
16
16
|
|
|
17
|
-
setKeys(prev => {
|
|
17
|
+
setKeys((prev) => {
|
|
18
18
|
const newKeys = new Set(prev)
|
|
19
19
|
|
|
20
20
|
newKeys.add(mapKey(event.code))
|
package/src/validators.ts
CHANGED
|
@@ -24,7 +24,9 @@ export function isHotkeyEnabledOnTag({ target }: KeyboardEvent, enabledOnTags: F
|
|
|
24
24
|
const targetTagName = target && (target as HTMLElement).tagName
|
|
25
25
|
|
|
26
26
|
if (enabledOnTags instanceof Array) {
|
|
27
|
-
return Boolean(
|
|
27
|
+
return Boolean(
|
|
28
|
+
targetTagName && enabledOnTags && enabledOnTags.some((tag) => tag.toLowerCase() === targetTagName.toLowerCase())
|
|
29
|
+
)
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
return Boolean(targetTagName && enabledOnTags && enabledOnTags === true)
|
|
@@ -33,7 +35,7 @@ export function isHotkeyEnabledOnTag({ target }: KeyboardEvent, enabledOnTags: F
|
|
|
33
35
|
export function isScopeActive(activeScopes: string[], scopes?: Scopes): boolean {
|
|
34
36
|
if (activeScopes.length === 0 && scopes) {
|
|
35
37
|
console.warn(
|
|
36
|
-
'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>'
|
|
38
|
+
'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>'
|
|
37
39
|
)
|
|
38
40
|
|
|
39
41
|
return true
|
|
@@ -43,10 +45,10 @@ export function isScopeActive(activeScopes: string[], scopes?: Scopes): boolean
|
|
|
43
45
|
return true
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
return activeScopes.some(scope => scopes.includes(scope)) || activeScopes.includes('*')
|
|
48
|
+
return activeScopes.some((scope) => scopes.includes(scope)) || activeScopes.includes('*')
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
export const isHotkeyMatchingKeyboardEvent = (e: KeyboardEvent, hotkey: Hotkey, ignoreModifiers
|
|
51
|
+
export const isHotkeyMatchingKeyboardEvent = (e: KeyboardEvent, hotkey: Hotkey, ignoreModifiers = false): boolean => {
|
|
50
52
|
const { alt, meta, mod, shift, ctrl, keys } = hotkey
|
|
51
53
|
const { key: pressedKeyUppercase, code, ctrlKey, metaKey, shiftKey, altKey } = e
|
|
52
54
|
|