react-hotkeys-hook 5.0.1 → 5.1.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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createContext as
|
|
2
|
-
import { jsx as
|
|
3
|
-
const
|
|
1
|
+
import { createContext as W, useContext as z, useState as A, useCallback as v, useRef as H, useLayoutEffect as _, useEffect as m } from "react";
|
|
2
|
+
import { jsx as q } from "react/jsx-runtime";
|
|
3
|
+
const G = ["shift", "alt", "meta", "mod", "ctrl", "control"], O = {
|
|
4
4
|
esc: "escape",
|
|
5
5
|
return: "enter",
|
|
6
6
|
left: "arrowleft",
|
|
@@ -18,99 +18,106 @@ const F = ["shift", "alt", "meta", "mod", "ctrl", "control"], V = {
|
|
|
18
18
|
ControlLeft: "ctrl",
|
|
19
19
|
ControlRight: "ctrl"
|
|
20
20
|
};
|
|
21
|
-
function
|
|
22
|
-
return (
|
|
21
|
+
function S(t) {
|
|
22
|
+
return (O[t.trim()] || t.trim()).toLowerCase().replace(/key|digit|numpad/, "");
|
|
23
23
|
}
|
|
24
|
-
function
|
|
25
|
-
return
|
|
24
|
+
function J(t) {
|
|
25
|
+
return G.includes(t);
|
|
26
26
|
}
|
|
27
|
-
function
|
|
27
|
+
function b(t, r = ",") {
|
|
28
28
|
return t.toLowerCase().split(r);
|
|
29
29
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
function R(t, r = "+", n = ">", f = !1, l) {
|
|
31
|
+
let u = [], c = !1;
|
|
32
|
+
t.includes(n) ? (c = !0, u = t.toLocaleLowerCase().split(n).map((i) => S(i))) : u = t.toLocaleLowerCase().split(r).map((i) => S(i));
|
|
33
|
+
const d = {
|
|
34
|
+
alt: u.includes("alt"),
|
|
35
|
+
ctrl: u.includes("ctrl") || u.includes("control"),
|
|
36
|
+
shift: u.includes("shift"),
|
|
37
|
+
meta: u.includes("meta"),
|
|
38
|
+
mod: u.includes("mod"),
|
|
39
|
+
useKey: f
|
|
40
|
+
}, a = u.filter((i) => !G.includes(i));
|
|
39
41
|
return {
|
|
40
|
-
...
|
|
41
|
-
keys:
|
|
42
|
-
description:
|
|
42
|
+
...d,
|
|
43
|
+
keys: a,
|
|
44
|
+
description: l,
|
|
45
|
+
isSequence: c
|
|
43
46
|
};
|
|
44
47
|
}
|
|
45
48
|
typeof document < "u" && (document.addEventListener("keydown", (t) => {
|
|
46
|
-
t.code !== void 0 &&
|
|
49
|
+
t.code !== void 0 && Q([S(t.code)]);
|
|
47
50
|
}), document.addEventListener("keyup", (t) => {
|
|
48
|
-
t.code !== void 0 &&
|
|
49
|
-
})), typeof window < "u" && window.addEventListener("blur", () => {
|
|
50
|
-
|
|
51
|
-
})
|
|
52
|
-
|
|
51
|
+
t.code !== void 0 && U([S(t.code)]);
|
|
52
|
+
})), typeof window < "u" && (window.addEventListener("blur", () => {
|
|
53
|
+
E.clear();
|
|
54
|
+
}), window.addEventListener("contextmenu", () => {
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
E.clear();
|
|
57
|
+
}, 0);
|
|
58
|
+
}));
|
|
59
|
+
const E = /* @__PURE__ */ new Set();
|
|
53
60
|
function B(t) {
|
|
54
61
|
return Array.isArray(t);
|
|
55
62
|
}
|
|
56
|
-
function
|
|
57
|
-
return (B(t) ? t : t.split(r)).every((
|
|
63
|
+
function ee(t, r = ",") {
|
|
64
|
+
return (B(t) ? t : t.split(r)).every((f) => E.has(f.trim().toLowerCase()));
|
|
58
65
|
}
|
|
59
|
-
function
|
|
66
|
+
function Q(t) {
|
|
60
67
|
const r = Array.isArray(t) ? t : [t];
|
|
61
|
-
|
|
68
|
+
E.has("meta") && E.forEach((n) => !J(n) && E.delete(n.toLowerCase())), r.forEach((n) => E.add(n.toLowerCase()));
|
|
62
69
|
}
|
|
63
|
-
function
|
|
70
|
+
function U(t) {
|
|
64
71
|
const r = Array.isArray(t) ? t : [t];
|
|
65
|
-
t === "meta" ?
|
|
72
|
+
t === "meta" ? E.clear() : r.forEach((n) => E.delete(n.toLowerCase()));
|
|
66
73
|
}
|
|
67
|
-
function
|
|
74
|
+
function te(t, r, n) {
|
|
68
75
|
(typeof n == "function" && n(t, r) || n === !0) && t.preventDefault();
|
|
69
76
|
}
|
|
70
|
-
function
|
|
77
|
+
function re(t, r, n) {
|
|
71
78
|
return typeof n == "function" ? n(t, r) : n === !0 || n === void 0;
|
|
72
79
|
}
|
|
73
|
-
function
|
|
74
|
-
return
|
|
80
|
+
function ne(t) {
|
|
81
|
+
return V(t, ["input", "textarea", "select"]);
|
|
75
82
|
}
|
|
76
|
-
function
|
|
77
|
-
const { target: n, composed:
|
|
78
|
-
let
|
|
79
|
-
return
|
|
83
|
+
function V(t, r = !1) {
|
|
84
|
+
const { target: n, composed: f } = t;
|
|
85
|
+
let l;
|
|
86
|
+
return ce(n) && f ? l = t.composedPath()[0] && t.composedPath()[0].tagName : l = n && n.tagName, B(r) ? !!(l && r && r.some((u) => u.toLowerCase() === l.toLowerCase())) : !!(l && r && r);
|
|
80
87
|
}
|
|
81
|
-
function
|
|
88
|
+
function ce(t) {
|
|
82
89
|
return !!t.tagName && !t.tagName.startsWith("-") && t.tagName.includes("-");
|
|
83
90
|
}
|
|
84
|
-
function
|
|
91
|
+
function ue(t, r) {
|
|
85
92
|
return t.length === 0 && r ? (console.warn(
|
|
86
93
|
'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>'
|
|
87
94
|
), !0) : r ? t.some((n) => r.includes(n)) || t.includes("*") : !0;
|
|
88
95
|
}
|
|
89
|
-
const
|
|
90
|
-
const { alt:
|
|
91
|
-
if (
|
|
96
|
+
const oe = (t, r, n = !1) => {
|
|
97
|
+
const { alt: f, meta: l, mod: u, shift: c, ctrl: d, keys: a, useKey: i } = r, { code: w, key: e, ctrlKey: s, metaKey: y, shiftKey: k, altKey: K } = t, h = S(w);
|
|
98
|
+
if (i && (a == null ? void 0 : a.length) === 1 && a.includes(e))
|
|
92
99
|
return !0;
|
|
93
|
-
if (!(
|
|
100
|
+
if (!(a != null && a.includes(h)) && !["ctrl", "control", "unknown", "meta", "alt", "shift", "os"].includes(h))
|
|
94
101
|
return !1;
|
|
95
102
|
if (!n) {
|
|
96
|
-
if (
|
|
103
|
+
if (f !== K && h !== "alt" || c !== k && h !== "shift")
|
|
97
104
|
return !1;
|
|
98
|
-
if (
|
|
99
|
-
if (!
|
|
105
|
+
if (u) {
|
|
106
|
+
if (!y && !s)
|
|
100
107
|
return !1;
|
|
101
|
-
} else if (
|
|
108
|
+
} else if (l !== y && h !== "meta" && h !== "os" || d !== s && h !== "ctrl" && h !== "control")
|
|
102
109
|
return !1;
|
|
103
110
|
}
|
|
104
|
-
return
|
|
105
|
-
},
|
|
106
|
-
function
|
|
107
|
-
return /* @__PURE__ */
|
|
111
|
+
return a && a.length === 1 && a.includes(h) ? !0 : a ? ee(a) : !a;
|
|
112
|
+
}, X = W(void 0), ae = () => z(X);
|
|
113
|
+
function fe({ addHotkey: t, removeHotkey: r, children: n }) {
|
|
114
|
+
return /* @__PURE__ */ q(X.Provider, { value: { addHotkey: t, removeHotkey: r }, children: n });
|
|
108
115
|
}
|
|
109
116
|
function N(t, r) {
|
|
110
117
|
return t && r && typeof t == "object" && typeof r == "object" ? Object.keys(t).length === Object.keys(r).length && // @ts-expect-error TS7053
|
|
111
|
-
Object.keys(t).reduce((n,
|
|
118
|
+
Object.keys(t).reduce((n, f) => n && N(t[f], r[f]), !0) : t === r;
|
|
112
119
|
}
|
|
113
|
-
const
|
|
120
|
+
const Y = W({
|
|
114
121
|
hotkeys: [],
|
|
115
122
|
activeScopes: [],
|
|
116
123
|
// This array has to be empty instead of containing '*' as default, to check if the provider is set or not
|
|
@@ -120,101 +127,120 @@ const J = I({
|
|
|
120
127
|
},
|
|
121
128
|
disableScope: () => {
|
|
122
129
|
}
|
|
123
|
-
}),
|
|
124
|
-
const [n,
|
|
125
|
-
|
|
126
|
-
}, []),
|
|
127
|
-
|
|
128
|
-
}, []),
|
|
129
|
-
|
|
130
|
-
}, []),
|
|
131
|
-
|
|
132
|
-
}, []),
|
|
133
|
-
|
|
130
|
+
}), le = () => z(Y), he = ({ initiallyActiveScopes: t = ["*"], children: r }) => {
|
|
131
|
+
const [n, f] = A(t), [l, u] = A([]), c = v((e) => {
|
|
132
|
+
f((s) => s.includes("*") ? [e] : Array.from(/* @__PURE__ */ new Set([...s, e])));
|
|
133
|
+
}, []), d = v((e) => {
|
|
134
|
+
f((s) => s.filter((y) => y !== e));
|
|
135
|
+
}, []), a = v((e) => {
|
|
136
|
+
f((s) => s.includes(e) ? s.filter((y) => y !== e) : s.includes("*") ? [e] : Array.from(/* @__PURE__ */ new Set([...s, e])));
|
|
137
|
+
}, []), i = v((e) => {
|
|
138
|
+
u((s) => [...s, e]);
|
|
139
|
+
}, []), w = v((e) => {
|
|
140
|
+
u((s) => s.filter((y) => !N(y, e)));
|
|
134
141
|
}, []);
|
|
135
|
-
return /* @__PURE__ */
|
|
136
|
-
|
|
142
|
+
return /* @__PURE__ */ q(
|
|
143
|
+
Y.Provider,
|
|
137
144
|
{
|
|
138
|
-
value: { activeScopes: n, hotkeys:
|
|
139
|
-
children: /* @__PURE__ */
|
|
145
|
+
value: { activeScopes: n, hotkeys: l, enableScope: c, disableScope: d, toggleScope: a },
|
|
146
|
+
children: /* @__PURE__ */ q(fe, { addHotkey: i, removeHotkey: w, children: r })
|
|
140
147
|
}
|
|
141
148
|
);
|
|
142
149
|
};
|
|
143
|
-
function
|
|
144
|
-
const r =
|
|
150
|
+
function se(t) {
|
|
151
|
+
const r = H(void 0);
|
|
145
152
|
return N(r.current, t) || (r.current = t), r.current;
|
|
146
153
|
}
|
|
147
|
-
const
|
|
154
|
+
const F = (t) => {
|
|
148
155
|
t.stopPropagation(), t.preventDefault(), t.stopImmediatePropagation();
|
|
149
|
-
},
|
|
150
|
-
function
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
const e =
|
|
154
|
-
return
|
|
155
|
-
if ((e == null ? void 0 : e.enabled) === !1 || !
|
|
156
|
+
}, ie = typeof window < "u" ? _ : m;
|
|
157
|
+
function we(t, r, n, f) {
|
|
158
|
+
const l = H(null), u = H(!1), c = n instanceof Array ? f instanceof Array ? void 0 : f : n, d = B(t) ? t.join(c == null ? void 0 : c.delimiter) : t, a = n instanceof Array ? n : f instanceof Array ? f : void 0, i = v(r, a ?? []), w = H(i);
|
|
159
|
+
a ? w.current = i : w.current = r;
|
|
160
|
+
const e = se(c), { activeScopes: s } = le(), y = ae();
|
|
161
|
+
return ie(() => {
|
|
162
|
+
if ((e == null ? void 0 : e.enabled) === !1 || !ue(s, e == null ? void 0 : e.scopes))
|
|
156
163
|
return;
|
|
157
|
-
|
|
164
|
+
let k = [], K;
|
|
165
|
+
const h = (o, M = !1) => {
|
|
158
166
|
var j;
|
|
159
|
-
if (!(
|
|
160
|
-
if (
|
|
161
|
-
const
|
|
162
|
-
if ((
|
|
163
|
-
|
|
167
|
+
if (!(ne(o) && !V(o, e == null ? void 0 : e.enableOnFormTags))) {
|
|
168
|
+
if (l.current !== null) {
|
|
169
|
+
const L = l.current.getRootNode();
|
|
170
|
+
if ((L instanceof Document || L instanceof ShadowRoot) && L.activeElement !== l.current && !l.current.contains(L.activeElement)) {
|
|
171
|
+
F(o);
|
|
164
172
|
return;
|
|
165
173
|
}
|
|
166
174
|
}
|
|
167
|
-
(j =
|
|
168
|
-
var
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
175
|
+
(j = o.target) != null && j.isContentEditable && !(e != null && e.enableOnContentEditable) || b(d, e == null ? void 0 : e.delimiter).forEach((L) => {
|
|
176
|
+
var D, I, p, $;
|
|
177
|
+
if (L.includes((e == null ? void 0 : e.splitKey) ?? "+") && L.includes((e == null ? void 0 : e.sequenceSplitKey) ?? ">")) {
|
|
178
|
+
console.warn(`Hotkey ${L} contains both ${(e == null ? void 0 : e.splitKey) ?? "+"} and ${(e == null ? void 0 : e.sequenceSplitKey) ?? ">"} which is not supported.`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const g = R(L, e == null ? void 0 : e.splitKey, e == null ? void 0 : e.sequenceSplitKey, e == null ? void 0 : e.useKey, e == null ? void 0 : e.description);
|
|
182
|
+
if (g.isSequence) {
|
|
183
|
+
K = setTimeout(() => {
|
|
184
|
+
k = [];
|
|
185
|
+
}, (e == null ? void 0 : e.sequenceTimeoutMs) ?? 1e3);
|
|
186
|
+
const P = g.useKey ? o.key : S(o.code);
|
|
187
|
+
if (J(P.toLowerCase()))
|
|
188
|
+
return;
|
|
189
|
+
k.push(P);
|
|
190
|
+
const Z = (D = g.keys) == null ? void 0 : D[k.length - 1];
|
|
191
|
+
if (P !== Z) {
|
|
192
|
+
k = [], K && clearTimeout(K);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
k.length === ((I = g.keys) == null ? void 0 : I.length) && (w.current(o, g), K && clearTimeout(K), k = []);
|
|
196
|
+
} else if (oe(o, g, e == null ? void 0 : e.ignoreModifiers) || (p = g.keys) != null && p.includes("*")) {
|
|
197
|
+
if (($ = e == null ? void 0 : e.ignoreEventWhen) != null && $.call(e, o) || M && u.current)
|
|
172
198
|
return;
|
|
173
|
-
if (
|
|
174
|
-
|
|
199
|
+
if (te(o, g, e == null ? void 0 : e.preventDefault), !re(o, g, e == null ? void 0 : e.enabled)) {
|
|
200
|
+
F(o);
|
|
175
201
|
return;
|
|
176
202
|
}
|
|
177
|
-
|
|
203
|
+
w.current(o, g), M || (u.current = !0);
|
|
178
204
|
}
|
|
179
205
|
});
|
|
180
206
|
}
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
},
|
|
184
|
-
|
|
185
|
-
},
|
|
186
|
-
return
|
|
187
|
-
(
|
|
188
|
-
|
|
207
|
+
}, T = (o) => {
|
|
208
|
+
o.code !== void 0 && (Q(S(o.code)), ((e == null ? void 0 : e.keydown) === void 0 && (e == null ? void 0 : e.keyup) !== !0 || e != null && e.keydown) && h(o));
|
|
209
|
+
}, x = (o) => {
|
|
210
|
+
o.code !== void 0 && (U(S(o.code)), u.current = !1, e != null && e.keyup && h(o, !0));
|
|
211
|
+
}, C = l.current || (c == null ? void 0 : c.document) || document;
|
|
212
|
+
return C.addEventListener("keyup", x, c == null ? void 0 : c.eventListenerOptions), C.addEventListener("keydown", T, c == null ? void 0 : c.eventListenerOptions), y && b(d, e == null ? void 0 : e.delimiter).forEach(
|
|
213
|
+
(o) => y.addHotkey(
|
|
214
|
+
R(o, e == null ? void 0 : e.splitKey, e == null ? void 0 : e.sequenceSplitKey, e == null ? void 0 : e.useKey, e == null ? void 0 : e.description)
|
|
189
215
|
)
|
|
190
216
|
), () => {
|
|
191
|
-
|
|
192
|
-
(
|
|
193
|
-
|
|
217
|
+
C.removeEventListener("keyup", x, c == null ? void 0 : c.eventListenerOptions), C.removeEventListener("keydown", T, c == null ? void 0 : c.eventListenerOptions), y && b(d, e == null ? void 0 : e.delimiter).forEach(
|
|
218
|
+
(o) => y.removeHotkey(
|
|
219
|
+
R(o, e == null ? void 0 : e.splitKey, e == null ? void 0 : e.sequenceSplitKey, e == null ? void 0 : e.useKey, e == null ? void 0 : e.description)
|
|
194
220
|
)
|
|
195
|
-
);
|
|
221
|
+
), k = [], K && clearTimeout(K);
|
|
196
222
|
};
|
|
197
|
-
}, [
|
|
223
|
+
}, [d, e, s]), l;
|
|
198
224
|
}
|
|
199
|
-
function
|
|
200
|
-
const [r, n] = A(/* @__PURE__ */ new Set()), [
|
|
201
|
-
|
|
202
|
-
const e = new Set(
|
|
203
|
-
return e.add(
|
|
225
|
+
function ge(t = !1) {
|
|
226
|
+
const [r, n] = A(/* @__PURE__ */ new Set()), [f, l] = A(!1), u = v((i) => {
|
|
227
|
+
i.code !== void 0 && (i.preventDefault(), i.stopPropagation(), n((w) => {
|
|
228
|
+
const e = new Set(w);
|
|
229
|
+
return e.add(S(t ? i.key : i.code)), e;
|
|
204
230
|
}));
|
|
205
|
-
}, [t]),
|
|
206
|
-
typeof document < "u" && (document.removeEventListener("keydown",
|
|
207
|
-
}, [
|
|
208
|
-
n(/* @__PURE__ */ new Set()), typeof document < "u" && (
|
|
209
|
-
}, [
|
|
231
|
+
}, [t]), c = v(() => {
|
|
232
|
+
typeof document < "u" && (document.removeEventListener("keydown", u), l(!1));
|
|
233
|
+
}, [u]), d = v(() => {
|
|
234
|
+
n(/* @__PURE__ */ new Set()), typeof document < "u" && (c(), document.addEventListener("keydown", u), l(!0));
|
|
235
|
+
}, [u, c]), a = v(() => {
|
|
210
236
|
n(/* @__PURE__ */ new Set());
|
|
211
237
|
}, []);
|
|
212
|
-
return [r, { start:
|
|
238
|
+
return [r, { start: d, stop: c, resetKeys: a, isRecording: f }];
|
|
213
239
|
}
|
|
214
240
|
export {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
241
|
+
he as HotkeysProvider,
|
|
242
|
+
ee as isHotkeyPressed,
|
|
243
|
+
we as useHotkeys,
|
|
244
|
+
le as useHotkeysContext,
|
|
245
|
+
ge as useRecordHotkeys
|
|
220
246
|
};
|
|
@@ -2,4 +2,4 @@ import { Hotkey } from './types';
|
|
|
2
2
|
export declare function mapCode(key: string): string;
|
|
3
3
|
export declare function isHotkeyModifier(key: string): boolean;
|
|
4
4
|
export declare function parseKeysHookInput(keys: string, delimiter?: string): string[];
|
|
5
|
-
export declare function parseHotkey(hotkey: string, splitKey?: string, useKey?: boolean, description?: string): Hotkey;
|
|
5
|
+
export declare function parseHotkey(hotkey: string, splitKey?: string, sequenceSplitKey?: string, useKey?: boolean, description?: string): Hotkey;
|
|
@@ -2,7 +2,6 @@ import { DependencyList } from 'react';
|
|
|
2
2
|
export type FormTags = 'input' | 'textarea' | 'select' | 'INPUT' | 'TEXTAREA' | 'SELECT';
|
|
3
3
|
export type Keys = string | readonly string[];
|
|
4
4
|
export type Scopes = string | readonly string[];
|
|
5
|
-
export type RefType<T> = T | null;
|
|
6
5
|
export type EventListenerOptions = {
|
|
7
6
|
capture?: boolean;
|
|
8
7
|
once?: boolean;
|
|
@@ -21,6 +20,7 @@ export type Hotkey = KeyboardModifiers & {
|
|
|
21
20
|
keys?: readonly string[];
|
|
22
21
|
scopes?: Scopes;
|
|
23
22
|
description?: string;
|
|
23
|
+
isSequence?: boolean;
|
|
24
24
|
};
|
|
25
25
|
export type HotkeysEvent = Hotkey;
|
|
26
26
|
export type HotkeyCallback = (keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => void;
|
|
@@ -41,5 +41,7 @@ export type Options = {
|
|
|
41
41
|
ignoreModifiers?: boolean;
|
|
42
42
|
eventListenerOptions?: EventListenerOptions;
|
|
43
43
|
useKey?: boolean;
|
|
44
|
+
sequenceTimeoutMs?: number;
|
|
45
|
+
sequenceSplitKey?: string;
|
|
44
46
|
};
|
|
45
47
|
export type OptionsOrDependencyArray = Options | DependencyList;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { HotkeyCallback, Keys, OptionsOrDependencyArray
|
|
2
|
-
export default function useHotkeys<T extends HTMLElement>(keys: Keys, callback: HotkeyCallback, options?: OptionsOrDependencyArray, dependencies?: OptionsOrDependencyArray): import('react').RefObject<
|
|
1
|
+
import { HotkeyCallback, Keys, OptionsOrDependencyArray } from './types';
|
|
2
|
+
export default function useHotkeys<T extends HTMLElement>(keys: Keys, callback: HotkeyCallback, options?: OptionsOrDependencyArray, dependencies?: OptionsOrDependencyArray): import('react').RefObject<T | null>;
|