UNPKG

5.95 kBJavaScriptView Raw
1/*
2 * Copyright 2021 Palantir Technologies, Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import { __spreadArray } from "tslib";
17import * as React from "react";
18import { HOTKEYS_PROVIDER_NOT_FOUND } from "../../common/errors";
19import { elementIsTextInput } from "../../common/utils/domUtils";
20import { comboMatches, getKeyCombo, parseKeyCombo } from "../../components/hotkeys/hotkeyParser";
21import { HotkeysContext } from "../../context";
22/**
23 * React hook to register global and local hotkeys for a component.
24 *
25 * @see https://blueprintjs.com/docs/#core/hooks/use-hotkeys
26 * @param keys list of hotkeys to configure
27 * @param options hook options
28 */
29export function useHotkeys(keys, options) {
30 if (options === void 0) { options = {}; }
31 var _a = options.document, document = _a === void 0 ? getDefaultDocument() : _a, _b = options.showDialogKeyCombo, showDialogKeyCombo = _b === void 0 ? "?" : _b;
32 var localKeys = React.useMemo(function () {
33 return keys
34 .filter(function (k) { return !k.global; })
35 .map(function (k) { return ({
36 combo: parseKeyCombo(k.combo),
37 config: k,
38 }); });
39 }, [keys]);
40 var globalKeys = React.useMemo(function () {
41 return keys
42 .filter(function (k) { return k.global; })
43 .map(function (k) { return ({
44 combo: parseKeyCombo(k.combo),
45 config: k,
46 }); });
47 }, [keys]);
48 // register keys with global context
49 var _c = React.useContext(HotkeysContext), state = _c[0], dispatch = _c[1];
50 React.useEffect(function () {
51 if (!state.hasProvider) {
52 console.warn(HOTKEYS_PROVIDER_NOT_FOUND);
53 }
54 }, [state.hasProvider]);
55 // we can still bind the hotkeys if there is no HotkeysProvider, they just won't show up in the dialog
56 React.useEffect(function () {
57 var payload = __spreadArray(__spreadArray([], globalKeys.map(function (k) { return k.config; }), true), localKeys.map(function (k) { return k.config; }), true);
58 dispatch({ type: "ADD_HOTKEYS", payload: payload });
59 return function () { return dispatch({ type: "REMOVE_HOTKEYS", payload: payload }); };
60 }, [dispatch, globalKeys, localKeys]);
61 var invokeNamedCallbackIfComboRecognized = React.useCallback(function (global, combo, callbackName, e) {
62 var _a, _b;
63 var isTextInput = elementIsTextInput(e.target);
64 for (var _i = 0, _c = global ? globalKeys : localKeys; _i < _c.length; _i++) {
65 var key = _c[_i];
66 var _d = key.config, _e = _d.allowInInput, allowInInput = _e === void 0 ? false : _e, _f = _d.disabled, disabled = _f === void 0 ? false : _f, _g = _d.preventDefault, preventDefault = _g === void 0 ? false : _g, _h = _d.stopPropagation, stopPropagation = _h === void 0 ? false : _h;
67 var shouldIgnore = (isTextInput && !allowInInput) || disabled;
68 if (!shouldIgnore && comboMatches(key.combo, combo)) {
69 if (preventDefault) {
70 e.preventDefault();
71 }
72 if (stopPropagation) {
73 // set a flag just for unit testing. not meant to be referenced in feature work.
74 e.isPropagationStopped = true;
75 e.stopPropagation();
76 }
77 (_b = (_a = key.config)[callbackName]) === null || _b === void 0 ? void 0 : _b.call(_a, e);
78 }
79 }
80 }, [globalKeys, localKeys]);
81 var handleGlobalKeyDown = React.useCallback(function (e) {
82 // special case for global keydown: if '?' is pressed, open the hotkeys dialog
83 var combo = getKeyCombo(e);
84 var isTextInput = elementIsTextInput(e.target);
85 if (!isTextInput && comboMatches(parseKeyCombo(showDialogKeyCombo), combo)) {
86 dispatch({ type: "OPEN_DIALOG" });
87 }
88 else {
89 invokeNamedCallbackIfComboRecognized(true, getKeyCombo(e), "onKeyDown", e);
90 }
91 }, [dispatch, invokeNamedCallbackIfComboRecognized, showDialogKeyCombo]);
92 var handleGlobalKeyUp = React.useCallback(function (e) { return invokeNamedCallbackIfComboRecognized(true, getKeyCombo(e), "onKeyUp", e); }, [invokeNamedCallbackIfComboRecognized]);
93 var handleLocalKeyDown = React.useCallback(function (e) {
94 return invokeNamedCallbackIfComboRecognized(false, getKeyCombo(e.nativeEvent), "onKeyDown", e.nativeEvent);
95 }, [invokeNamedCallbackIfComboRecognized]);
96 var handleLocalKeyUp = React.useCallback(function (e) {
97 return invokeNamedCallbackIfComboRecognized(false, getKeyCombo(e.nativeEvent), "onKeyUp", e.nativeEvent);
98 }, [invokeNamedCallbackIfComboRecognized]);
99 React.useEffect(function () {
100 // document is guaranteed to be defined inside effects
101 document.addEventListener("keydown", handleGlobalKeyDown);
102 document.addEventListener("keyup", handleGlobalKeyUp);
103 return function () {
104 document.removeEventListener("keydown", handleGlobalKeyDown);
105 document.removeEventListener("keyup", handleGlobalKeyUp);
106 };
107 }, [handleGlobalKeyDown, handleGlobalKeyUp]);
108 return { handleKeyDown: handleLocalKeyDown, handleKeyUp: handleLocalKeyUp };
109}
110function getDefaultDocument() {
111 if (typeof window === "undefined") {
112 return undefined;
113 }
114 return window.document;
115}
116//# sourceMappingURL=useHotkeys.js.map
\No newline at end of file