@reecelucas/react-use-hotkeys
Advanced tools
Comparing version 1.3.5 to 2.0.0
@@ -0,3 +1,10 @@ | ||
import type { ElementsToIgnore } from "./helpers/ignoreKeydownEvent"; | ||
import "./vendor/shim-keyboard-event-key"; | ||
declare const useHotkeys: (hotkeys: string | string[], callback: (event: KeyboardEvent) => void, eventListenerOptions?: boolean | AddEventListenerOptions) => void; | ||
interface Options { | ||
enabled?: boolean; | ||
enableOnContentEditable?: boolean; | ||
ignoredElementWhitelist?: ElementsToIgnore[]; | ||
eventListenerOptions?: AddEventListenerOptions; | ||
} | ||
declare const useHotkeys: (hotkeys: string | string[], callback: (event: KeyboardEvent) => void, options?: Options) => void; | ||
export default useHotkeys; |
@@ -10,6 +10,7 @@ import { useEffect, useMemo } from "react"; | ||
import takeUntilLast from "./helpers/takeUntilLast"; | ||
import ignoreKeydownEvent from "./helpers/ignoreKeydownEvent"; | ||
import "./vendor/shim-keyboard-event-key"; | ||
var KEY_SEQUENCE_TIMEOUT = 1000; | ||
var ESCAPE_HATCH_KEY = "*"; | ||
var useHotkeys = function (hotkeys, callback, eventListenerOptions) { | ||
var useHotkeys = function (hotkeys, callback, options) { | ||
var hotkeysArray = useMemo(function () { | ||
@@ -23,2 +24,3 @@ return Array.isArray(hotkeys) | ||
var sequenceTimers = {}; | ||
var _a = options || {}, enabled = _a.enabled, enableOnContentEditable = _a.enableOnContentEditable, ignoredElementWhitelist = _a.ignoredElementWhitelist, eventListenerOptions = _a.eventListenerOptions; | ||
var clearSequenceTimer = function (index) { | ||
@@ -54,7 +56,3 @@ clearTimeout(sequenceTimers[index]); | ||
var onKeydown = function (event) { | ||
/** | ||
* Chrome autocomplete triggers `keydown` event but event.key will be undefined. | ||
* See https://bugs.chromium.org/p/chromium/issues/detail?id=581537. | ||
*/ | ||
if (!event.key && !modifierKeyPressed(event)) { | ||
if (ignoreKeydownEvent(event, enableOnContentEditable, ignoredElementWhitelist)) { | ||
return; | ||
@@ -87,8 +85,17 @@ } | ||
}; | ||
window.addEventListener("keydown", onKeydown, eventListenerOptions); | ||
if (enabled !== false) { | ||
window.addEventListener("keydown", onKeydown, eventListenerOptions); | ||
} | ||
return function () { | ||
window.removeEventListener("keydown", onKeydown, eventListenerOptions); | ||
}; | ||
}, [hotkeysArray, callback, eventListenerOptions]); | ||
}, [ | ||
hotkeysArray, | ||
callback, | ||
options === null || options === void 0 ? void 0 : options.enabled, | ||
options === null || options === void 0 ? void 0 : options.enableOnContentEditable, | ||
options === null || options === void 0 ? void 0 : options.ignoredElementWhitelist, | ||
options === null || options === void 0 ? void 0 : options.eventListenerOptions, | ||
]); | ||
}; | ||
export default useHotkeys; |
@@ -0,3 +1,10 @@ | ||
import type { ElementsToIgnore } from "./helpers/ignoreKeydownEvent"; | ||
import "./vendor/shim-keyboard-event-key"; | ||
declare const useHotkeys: (hotkeys: string | string[], callback: (event: KeyboardEvent) => void, eventListenerOptions?: boolean | AddEventListenerOptions) => void; | ||
interface Options { | ||
enabled?: boolean; | ||
enableOnContentEditable?: boolean; | ||
ignoredElementWhitelist?: ElementsToIgnore[]; | ||
eventListenerOptions?: AddEventListenerOptions; | ||
} | ||
declare const useHotkeys: (hotkeys: string | string[], callback: (event: KeyboardEvent) => void, options?: Options) => void; | ||
export default useHotkeys; |
@@ -12,6 +12,7 @@ "use strict"; | ||
var takeUntilLast_1 = require("./helpers/takeUntilLast"); | ||
var ignoreKeydownEvent_1 = require("./helpers/ignoreKeydownEvent"); | ||
require("./vendor/shim-keyboard-event-key"); | ||
var KEY_SEQUENCE_TIMEOUT = 1000; | ||
var ESCAPE_HATCH_KEY = "*"; | ||
var useHotkeys = function (hotkeys, callback, eventListenerOptions) { | ||
var useHotkeys = function (hotkeys, callback, options) { | ||
var hotkeysArray = (0, react_1.useMemo)(function () { | ||
@@ -25,2 +26,3 @@ return Array.isArray(hotkeys) | ||
var sequenceTimers = {}; | ||
var _a = options || {}, enabled = _a.enabled, enableOnContentEditable = _a.enableOnContentEditable, ignoredElementWhitelist = _a.ignoredElementWhitelist, eventListenerOptions = _a.eventListenerOptions; | ||
var clearSequenceTimer = function (index) { | ||
@@ -56,7 +58,3 @@ clearTimeout(sequenceTimers[index]); | ||
var onKeydown = function (event) { | ||
/** | ||
* Chrome autocomplete triggers `keydown` event but event.key will be undefined. | ||
* See https://bugs.chromium.org/p/chromium/issues/detail?id=581537. | ||
*/ | ||
if (!event.key && !(0, modifierKeyPressed_1.default)(event)) { | ||
if ((0, ignoreKeydownEvent_1.default)(event, enableOnContentEditable, ignoredElementWhitelist)) { | ||
return; | ||
@@ -89,8 +87,17 @@ } | ||
}; | ||
window.addEventListener("keydown", onKeydown, eventListenerOptions); | ||
if (enabled !== false) { | ||
window.addEventListener("keydown", onKeydown, eventListenerOptions); | ||
} | ||
return function () { | ||
window.removeEventListener("keydown", onKeydown, eventListenerOptions); | ||
}; | ||
}, [hotkeysArray, callback, eventListenerOptions]); | ||
}, [ | ||
hotkeysArray, | ||
callback, | ||
options === null || options === void 0 ? void 0 : options.enabled, | ||
options === null || options === void 0 ? void 0 : options.enableOnContentEditable, | ||
options === null || options === void 0 ? void 0 : options.ignoredElementWhitelist, | ||
options === null || options === void 0 ? void 0 : options.eventListenerOptions, | ||
]); | ||
}; | ||
exports.default = useHotkeys; |
{ | ||
"name": "@reecelucas/react-use-hotkeys", | ||
"version": "1.3.5", | ||
"version": "2.0.0", | ||
"description": "React hook to create keyboard shortcuts", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
127
README.md
@@ -19,2 +19,6 @@ # react-use-hotkeys | ||
```ts | ||
import useHotkeys from "@reecelucas/react-use-hotkeys"; | ||
``` | ||
All hotkey combinations must use valid `KeyBoardEvent` `"key"` values. A full list can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values) and Wes Bos has created a great [interactive lookup](https://keycode.info/). | ||
@@ -24,18 +28,18 @@ | ||
// Single keys | ||
useHotkeys('Escape', () => { | ||
console.log('Some action'); | ||
useHotkeys("Escape", () => { | ||
console.log("Some action"); | ||
}); | ||
useHotkeys('F7', () => { | ||
console.log('Some action'); | ||
useHotkeys("F7", () => { | ||
console.log("Some action"); | ||
}); | ||
// Modifier combinations | ||
useHotkeys('Meta+Shift+z', () => { | ||
console.log('Some action'); | ||
useHotkeys("Meta+Shift+z", () => { | ||
console.log("Some action"); | ||
}); | ||
// Key sequences | ||
useHotkeys('w s d', () => { | ||
console.log('Some action'); | ||
useHotkeys("w s d", () => { | ||
console.log("Some action"); | ||
}); | ||
@@ -45,13 +49,13 @@ | ||
// space key in sequence (`w ' ' d` also works) | ||
console.log('Some action'); | ||
console.log("Some action"); | ||
}); | ||
// Multiple key combinations mapped to the same callback | ||
useHotkeys(['Control+z', 'Meta+z'], () => { | ||
console.log('Some action'); | ||
useHotkeys(["Control+z", "Meta+z"], () => { | ||
console.log("Some action"); | ||
}); | ||
useHotkeys(['a', 'Meta+z', 'w s d'], () => { | ||
console.log('Some action'); | ||
}) | ||
useHotkeys(["a", "Meta+z", "w s d"], () => { | ||
console.log("Some action"); | ||
}); | ||
``` | ||
@@ -63,3 +67,3 @@ | ||
// Modifier keys in sequences | ||
useHotkeys('Control i d', () => { | ||
useHotkeys("Control i d", () => { | ||
console.log("I won't run!"); | ||
@@ -69,3 +73,3 @@ }); | ||
// Modifier combinations in sequences | ||
useHotkeys('Control+z i d', () => { | ||
useHotkeys("Control+z i d", () => { | ||
console.log("I won't run!"); | ||
@@ -75,24 +79,82 @@ }); | ||
You can pass `AddEventListenerOptions` if you need to listen for `keydown` events in the capturing phase: | ||
If you find a use case where the API is too restrictive you can use the escape hatch to perform whatever custom logic you need: | ||
```jsx | ||
useHotkeys('Escape', () => { | ||
console.log('Some action'); | ||
}, true); | ||
useHotkeys("*", (event) => { | ||
console.log("I will run on every keydown event"); | ||
useHotkeys('Escape', () => { | ||
console.log('Some action'); | ||
}, { capture: true }); | ||
if (customKeyLogic(event)) { | ||
console.log("some action"); | ||
} | ||
}); | ||
``` | ||
If you find a use case where the API is too restrictive you can use the escape hatch to perform whatever custom logic you need: | ||
## Options | ||
### `enabled` | ||
You can disable the hook by passing `enabled: false`. When disabled the hook will stop listening for `keydown` events: | ||
```jsx | ||
useHotkeys('*', event => { | ||
console.log("I will run on every keydown"); | ||
useHotkeys( | ||
"Escape", | ||
() => { | ||
console.log("I won't run!"); | ||
}, | ||
{ enabled: false } | ||
); | ||
``` | ||
if (customKeyLogic(event)) { | ||
console.log("some action"); | ||
### `enableOnContentEditable` | ||
By default, the hook will ignore `keydown` events originating from elements with the `contenteditable` attribute, since this behaviour is normally what you want. If you want to override this behaviour you can pass `enableOnContentEditable: true`: | ||
```jsx | ||
useHotkeys( | ||
"Escape", | ||
() => { | ||
console.log("Some action"); | ||
}, | ||
{ enableOnContentEditable: true } | ||
); | ||
``` | ||
### `ignoredElementWhitelist` | ||
By default, the hook will ignore `keydown` events originating from `INPUT` and `TEXTAREA` elements, since this behaviour is normally what you want. If you want to override this behaviour you can use `ignoredElementWhitelist`: | ||
```jsx | ||
useHotkeys( | ||
"Escape", | ||
() => { | ||
console.log("I will now run on input elements"); | ||
}, | ||
{ ignoredElementWhitelist: ["INPUT"] } | ||
); | ||
useHotkeys( | ||
"Escape", | ||
() => { | ||
console.log("I will now run on input and textarea elements"); | ||
}, | ||
{ ignoredElementWhitelist: ["INPUT", "TEXTAREA"] } | ||
); | ||
``` | ||
### `eventListenerOptions` | ||
You can pass [`AddEventListenerOptions`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#parameters) if you need to listen for `keydown` events in the capturing phase: | ||
```jsx | ||
useHotkeys( | ||
"Escape", | ||
() => { | ||
console.log("I will run in the capturing phase"); | ||
}, | ||
{ | ||
eventListenerOptions: { | ||
capture: true, | ||
}, | ||
} | ||
}); | ||
); | ||
``` | ||
@@ -106,3 +168,8 @@ | ||
callback: (event: KeyboardEvent) => void, | ||
eventListenerOptions?: boolean | AddEventListenerOptions | ||
options?: { | ||
enabled?: boolean; | ||
enableOnContentEditable?: boolean; | ||
ignoredElementWhitelist?: ("INPUT" | "TEXTAREA")[]; | ||
eventListenerOptions?: AddEventListenerOptions; | ||
} | ||
) => void; | ||
@@ -109,0 +176,0 @@ ``` |
30593
47
574
185