react-hotkeys-hook 5.3.0 → 5.3.2
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/README.md +13 -12
- package/package.json +1 -1
- package/packages/react-hotkeys-hook/dist/index.js +45 -45
package/README.md
CHANGED
|
@@ -38,14 +38,12 @@ A React hook for using keyboard shortcuts in components in a declarative way.
|
|
|
38
38
|
|
|
39
39
|
## Quick Start
|
|
40
40
|
|
|
41
|
-
The easiest way to use the hook.
|
|
42
|
-
|
|
43
41
|
```jsx harmony
|
|
44
42
|
import { useHotkeys } from 'react-hotkeys-hook'
|
|
45
43
|
|
|
46
44
|
export const ExampleComponent = () => {
|
|
47
45
|
const [count, setCount] = useState(0)
|
|
48
|
-
useHotkeys('ctrl+k', () => setCount(
|
|
46
|
+
useHotkeys('ctrl+k', () => setCount(prevCount => prevCount + 1))
|
|
49
47
|
|
|
50
48
|
return (
|
|
51
49
|
<p>
|
|
@@ -150,15 +148,18 @@ All options are optional and have a default value which you can override to chan
|
|
|
150
148
|
| Option | Type | Default value | Description |
|
|
151
149
|
|--------------------------|--------------------------------------------------------------------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
152
150
|
| `enabled` | `boolean` or `(keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => boolean` | `true` | This option determines whether the hotkey is active or not. It can take a boolean (for example a flag from a state outside) or a function which gets executed once the hotkey is pressed. If the function returns `false` the hotkey won't get executed and all browser events are prevented. |
|
|
153
|
-
| `enableOnFormTags` | `boolean` or `FormTags[]` | `false` | By default hotkeys are
|
|
154
|
-
| `enableOnContentEditable` | `boolean` | `false` |
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
151
|
+
| `enableOnFormTags` | `boolean` or `FormTags[]` | `false` | By default, hotkeys are disabled when a form element is focused. This prevents accidental triggering while the user is typing. Set to `true` to enable on all form tags, or pass an array of specific tags (e.g. `['input', 'textarea', 'select']`) |
|
|
152
|
+
| `enableOnContentEditable` | `boolean` | `false` | Enable hotkeys on elements with the `contentEditable` attribute set to `true` |
|
|
153
|
+
| `splitKey` | `string` | `+` | Character that joins keys within a combination (e.g. `shift+a`). Change this if you need to listen for the `+` key itself |
|
|
154
|
+
| `delimiter` | `string` | `,` | Character that separates different hotkey combinations mapped to the same callback (e.g. `ctrl+a, shift+b`) |
|
|
157
155
|
| `scopes` | `string` or `string[]` | `*` | With scopes you can group hotkeys together. The default scope is the wildcard `*` which matches all hotkeys. Use the `<HotkeysProvider>` component to change active scopes. |
|
|
158
|
-
| `keyup` | `boolean` | `false` |
|
|
159
|
-
| `keydown` | `boolean` | `true` |
|
|
160
|
-
| `preventDefault` | `boolean` or `(keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => boolean` | `false` |
|
|
161
|
-
| `description`
|
|
156
|
+
| `keyup` | `boolean` | `false` | Trigger the callback on the browser's `keyup` event |
|
|
157
|
+
| `keydown` | `boolean` | `true` | Trigger the callback on the browser's `keydown` event. Set both `keyup` and `keydown` to `true` to trigger on both events |
|
|
158
|
+
| `preventDefault` | `boolean` or `(keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => boolean` | `false` | Prevent the browser's default behavior for the matched keystroke. Useful for overriding shortcuts like `meta+s`. Note: some browser shortcuts (e.g. `meta+w`) cannot be overridden |
|
|
159
|
+
| `description` | `string` | `undefined` | Human-readable description of what the hotkey does. Useful for building help panels |
|
|
160
|
+
| `useKey` | `boolean` | `false` | Listen to the produced character instead of the physical key code |
|
|
161
|
+
| `ignoreModifiers` | `boolean` | `false` | Ignore modifier keys when matching hotkeys |
|
|
162
|
+
| `sequenceTimeoutMs` | `number` | `1000` | Time window in milliseconds for sequential hotkeys |
|
|
162
163
|
|
|
163
164
|
|
|
164
165
|
#### Overloads
|
|
@@ -186,7 +187,7 @@ isHotkeyPressed(['esc', 'ctrl+s']) // Returns true if Escape or Ctrl+S are press
|
|
|
186
187
|
|
|
187
188
|
## Support
|
|
188
189
|
|
|
189
|
-
* Ask your question in
|
|
190
|
+
* Ask your question in [GitHub Discussions](https://github.com/JohannesKlauss/react-hotkeys-hook/discussions)
|
|
190
191
|
* Ask your question on [StackOverflow](https://stackoverflow.com/search?page=1&tab=Relevance&q=react-hotkeys-hook)
|
|
191
192
|
|
|
192
193
|
## Found an issue or have a feature request?
|
package/package.json
CHANGED
|
@@ -31,7 +31,7 @@ function $(e) {
|
|
|
31
31
|
function R(e, t = ",") {
|
|
32
32
|
return e.toLowerCase().split(t);
|
|
33
33
|
}
|
|
34
|
-
function O(e, t = "+", r = ">",
|
|
34
|
+
function O(e, t = "+", r = ">", u = !1, s, f) {
|
|
35
35
|
let d = [], l = !1;
|
|
36
36
|
e = e.trim(), e.includes(r) ? (l = !0, d = e.toLocaleLowerCase().split(r).map((y) => L(y))) : d = e.toLocaleLowerCase().split(t).map((y) => L(y));
|
|
37
37
|
const o = {
|
|
@@ -40,12 +40,12 @@ function O(e, t = "+", r = ">", i = !1, u, f) {
|
|
|
40
40
|
shift: d.includes("shift"),
|
|
41
41
|
meta: d.includes("meta"),
|
|
42
42
|
mod: d.includes("mod"),
|
|
43
|
-
useKey:
|
|
43
|
+
useKey: u
|
|
44
44
|
}, p = d.filter((y) => !F.includes(y));
|
|
45
45
|
return {
|
|
46
46
|
...o,
|
|
47
47
|
keys: p,
|
|
48
|
-
description:
|
|
48
|
+
description: s,
|
|
49
49
|
isSequence: l,
|
|
50
50
|
hotkey: e,
|
|
51
51
|
metadata: f
|
|
@@ -71,7 +71,7 @@ function D(e) {
|
|
|
71
71
|
return Array.isArray(e);
|
|
72
72
|
}
|
|
73
73
|
function te(e, t = ",") {
|
|
74
|
-
return (D(e) ? e : e.split(t)).every((
|
|
74
|
+
return (D(e) ? e : e.split(t)).every((u) => g.has(u.trim().toLowerCase()));
|
|
75
75
|
}
|
|
76
76
|
function z(e) {
|
|
77
77
|
const t = Array.isArray(e) ? e : [e];
|
|
@@ -107,33 +107,33 @@ const oe = [
|
|
|
107
107
|
"radio",
|
|
108
108
|
"textbox"
|
|
109
109
|
];
|
|
110
|
-
function
|
|
110
|
+
function ie(e) {
|
|
111
111
|
return J(e, oe);
|
|
112
112
|
}
|
|
113
113
|
function J(e, t = !1) {
|
|
114
|
-
const { target: r, composed:
|
|
115
|
-
let
|
|
116
|
-
return
|
|
114
|
+
const { target: r, composed: u } = e;
|
|
115
|
+
let s, f;
|
|
116
|
+
return se(r) && u ? (s = e.composedPath()[0] && e.composedPath()[0].tagName, f = e.composedPath()[0] && e.composedPath()[0].role) : (s = r && r.tagName, f = r && r.role), D(t) ? !!(s && t?.some((d) => d.toLowerCase() === s.toLowerCase() || d === f)) : !!(s && t && t);
|
|
117
117
|
}
|
|
118
|
-
function
|
|
118
|
+
function se(e) {
|
|
119
119
|
return !!e.tagName && !e.tagName.startsWith("-") && e.tagName.includes("-");
|
|
120
120
|
}
|
|
121
121
|
function ue(e, t) {
|
|
122
122
|
return e.length === 0 && t ? !1 : t ? e.some((r) => t.includes(r)) || e.includes("*") : !0;
|
|
123
123
|
}
|
|
124
124
|
const ce = (e, t, r = !1) => {
|
|
125
|
-
const { alt:
|
|
126
|
-
if (p && o?.length === 1 && o.includes(
|
|
125
|
+
const { alt: u, meta: s, mod: f, shift: d, ctrl: l, keys: o, useKey: p } = t, { code: y, key: i, ctrlKey: c, metaKey: n, shiftKey: E, altKey: C } = e, m = L(y);
|
|
126
|
+
if (p && o?.length === 1 && o.includes(i.toLowerCase()))
|
|
127
127
|
return !0;
|
|
128
128
|
if (!o?.includes(m) && !["ctrl", "control", "unknown", "meta", "alt", "shift", "os"].includes(m))
|
|
129
129
|
return !1;
|
|
130
130
|
if (!r) {
|
|
131
|
-
if (
|
|
131
|
+
if (u !== C && m !== "alt" || d !== E && m !== "shift")
|
|
132
132
|
return !1;
|
|
133
133
|
if (f) {
|
|
134
134
|
if (Z() ? !n : !c)
|
|
135
135
|
return !1;
|
|
136
|
-
} else if (
|
|
136
|
+
} else if (s !== n && m !== "meta" && m !== "os" || l !== c && m !== "ctrl" && m !== "control")
|
|
137
137
|
return !1;
|
|
138
138
|
}
|
|
139
139
|
return o && o.length === 1 && o.includes(m) ? !0 : o && o.length > 0 ? o.includes(m) ? te(o) : !1 : !o || o.length === 0;
|
|
@@ -143,7 +143,7 @@ function de({ addHotkey: e, removeHotkey: t, children: r }) {
|
|
|
143
143
|
}
|
|
144
144
|
function M(e, t) {
|
|
145
145
|
return e && t && typeof e == "object" && typeof t == "object" ? Object.keys(e).length === Object.keys(t).length && // @ts-expect-error TS7053
|
|
146
|
-
Object.keys(e).reduce((r,
|
|
146
|
+
Object.keys(e).reduce((r, u) => r && M(e[u], t[u]), !0) : e === t;
|
|
147
147
|
}
|
|
148
148
|
const U = j({
|
|
149
149
|
hotkeys: [],
|
|
@@ -156,21 +156,21 @@ const U = j({
|
|
|
156
156
|
disableScope: () => {
|
|
157
157
|
}
|
|
158
158
|
}), fe = () => W(U), ve = ({ initiallyActiveScopes: e = ["*"], children: t }) => {
|
|
159
|
-
const [r,
|
|
160
|
-
|
|
161
|
-
}, []), l = h((
|
|
162
|
-
|
|
163
|
-
}, []), o = h((
|
|
164
|
-
|
|
165
|
-
}, []), p = h((
|
|
166
|
-
f((c) => [...c,
|
|
167
|
-
}, []), y = h((
|
|
168
|
-
f((c) => c.filter((n) => !M(n,
|
|
159
|
+
const [r, u] = A(e), [s, f] = A([]), d = h((i) => {
|
|
160
|
+
u((c) => c.includes("*") ? [i] : Array.from(/* @__PURE__ */ new Set([...c, i])));
|
|
161
|
+
}, []), l = h((i) => {
|
|
162
|
+
u((c) => c.filter((n) => n !== i));
|
|
163
|
+
}, []), o = h((i) => {
|
|
164
|
+
u((c) => c.includes(i) ? c.filter((n) => n !== i) : c.includes("*") ? [i] : Array.from(/* @__PURE__ */ new Set([...c, i])));
|
|
165
|
+
}, []), p = h((i) => {
|
|
166
|
+
f((c) => [...c, i]);
|
|
167
|
+
}, []), y = h((i) => {
|
|
168
|
+
f((c) => c.filter((n) => !M(n, i)));
|
|
169
169
|
}, []);
|
|
170
170
|
return /* @__PURE__ */ x(
|
|
171
171
|
U.Provider,
|
|
172
172
|
{
|
|
173
|
-
value: { activeScopes: r, hotkeys:
|
|
173
|
+
value: { activeScopes: r, hotkeys: s, enableScope: d, disableScope: l, toggleScope: o },
|
|
174
174
|
children: /* @__PURE__ */ x(de, { addHotkey: p, removeHotkey: y, children: t })
|
|
175
175
|
}
|
|
176
176
|
);
|
|
@@ -184,12 +184,12 @@ const ye = (e) => {
|
|
|
184
184
|
}, me = typeof window < "u" ? X : I;
|
|
185
185
|
function pe(e) {
|
|
186
186
|
if (!e) return;
|
|
187
|
-
const { enabled: t, preventDefault: r, ignoreEventWhen:
|
|
188
|
-
return
|
|
187
|
+
const { enabled: t, preventDefault: r, ignoreEventWhen: u, ...s } = e;
|
|
188
|
+
return typeof t == "function" ? s : { ...s, enabled: t };
|
|
189
189
|
}
|
|
190
|
-
function we(e, t, r,
|
|
191
|
-
const [
|
|
192
|
-
y ? c.current =
|
|
190
|
+
function we(e, t, r, u) {
|
|
191
|
+
const [s, f] = A(null), d = h((w) => (f(w), () => f(null)), []), l = K(!1), o = Array.isArray(r) ? Array.isArray(u) ? void 0 : u : r, p = D(e) ? e.join(o?.delimiter) : e, y = Array.isArray(r) ? r : Array.isArray(u) ? u : void 0, i = h(t, y ?? []), c = K(i);
|
|
192
|
+
y ? c.current = i : c.current = t;
|
|
193
193
|
const n = le(pe(o)), E = K(o?.enabled);
|
|
194
194
|
E.current = o?.enabled;
|
|
195
195
|
const C = K(o?.preventDefault);
|
|
@@ -202,10 +202,10 @@ function we(e, t, r, i) {
|
|
|
202
202
|
return;
|
|
203
203
|
let w = [], S;
|
|
204
204
|
const q = (a, _ = !1) => {
|
|
205
|
-
if (!(
|
|
206
|
-
if (
|
|
207
|
-
const k =
|
|
208
|
-
if ((k instanceof Document || k instanceof ShadowRoot) && k.activeElement !==
|
|
205
|
+
if (!(ie(a) && !J(a, n?.enableOnFormTags))) {
|
|
206
|
+
if (s !== null) {
|
|
207
|
+
const k = s.getRootNode();
|
|
208
|
+
if ((k instanceof Document || k instanceof ShadowRoot) && k.activeElement !== s && !s.contains(k.activeElement)) {
|
|
209
209
|
ye(a);
|
|
210
210
|
return;
|
|
211
211
|
}
|
|
@@ -250,7 +250,7 @@ function we(e, t, r, i) {
|
|
|
250
250
|
a.code !== void 0 && (z(L(a.code)), (n?.keydown === void 0 && n?.keyup !== !0 || n?.keydown) && q(a));
|
|
251
251
|
}, N = (a) => {
|
|
252
252
|
a.code !== void 0 && (G(L(a.code)), l.current = !1, n?.keyup && q(a, !0));
|
|
253
|
-
}, H =
|
|
253
|
+
}, H = s || o?.document || document;
|
|
254
254
|
return H.addEventListener("keyup", N, o?.eventListenerOptions), H.addEventListener("keydown", B, o?.eventListenerOptions), b && R(p, n?.delimiter).forEach((a) => {
|
|
255
255
|
b.addHotkey(
|
|
256
256
|
O(
|
|
@@ -276,15 +276,15 @@ function we(e, t, r, i) {
|
|
|
276
276
|
);
|
|
277
277
|
}), w = [], S && clearTimeout(S);
|
|
278
278
|
};
|
|
279
|
-
}, [
|
|
279
|
+
}, [s, n, T, p]), d;
|
|
280
280
|
}
|
|
281
281
|
function ke(e = !1, t = []) {
|
|
282
|
-
const [r,
|
|
283
|
-
(
|
|
284
|
-
if (
|
|
282
|
+
const [r, u] = A(/* @__PURE__ */ new Set()), [s, f] = A(!1), d = Y(() => new Set(t.map((i) => i.toLowerCase())), [t]), l = h(
|
|
283
|
+
(i) => {
|
|
284
|
+
if (i.code === void 0)
|
|
285
285
|
return;
|
|
286
|
-
const c = L(e ?
|
|
287
|
-
d.has(c) || (
|
|
286
|
+
const c = L(e ? i.key : i.code).toLowerCase();
|
|
287
|
+
d.has(c) || (i.preventDefault(), i.stopPropagation(), u((n) => {
|
|
288
288
|
const E = new Set(n);
|
|
289
289
|
return E.add(c), E;
|
|
290
290
|
}));
|
|
@@ -293,16 +293,16 @@ function ke(e = !1, t = []) {
|
|
|
293
293
|
), o = h(() => {
|
|
294
294
|
f(!1);
|
|
295
295
|
}, []), p = h(() => {
|
|
296
|
-
|
|
296
|
+
u(/* @__PURE__ */ new Set()), f(!0);
|
|
297
297
|
}, []), y = h(() => {
|
|
298
|
-
|
|
298
|
+
u(/* @__PURE__ */ new Set());
|
|
299
299
|
}, []);
|
|
300
300
|
return I(() => {
|
|
301
|
-
if (typeof document < "u" &&
|
|
301
|
+
if (typeof document < "u" && s)
|
|
302
302
|
return document.addEventListener("keydown", l), () => {
|
|
303
303
|
document.removeEventListener("keydown", l);
|
|
304
304
|
};
|
|
305
|
-
}, [
|
|
305
|
+
}, [s, l]), [r, { start: p, stop: o, resetKeys: y, isRecording: s }];
|
|
306
306
|
}
|
|
307
307
|
export {
|
|
308
308
|
ve as HotkeysProvider,
|