react-hotkeys-hook 5.2.2 → 5.2.4

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.
Files changed (3) hide show
  1. package/README.md +222 -53
  2. package/dist/index.js +115 -125
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,54 +1,223 @@
1
- # React + TypeScript + Vite
2
-
3
- This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4
-
5
- Currently, two official plugins are available:
6
-
7
- - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8
- - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9
-
10
- ## Expanding the ESLint configuration
11
-
12
- If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
13
-
14
- ```js
15
- export default tseslint.config({
16
- extends: [
17
- // Remove ...tseslint.configs.recommended and replace with this
18
- ...tseslint.configs.recommendedTypeChecked,
19
- // Alternatively, use this for stricter rules
20
- ...tseslint.configs.strictTypeChecked,
21
- // Optionally, add this for stylistic rules
22
- ...tseslint.configs.stylisticTypeChecked,
23
- ],
24
- languageOptions: {
25
- // other options...
26
- parserOptions: {
27
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
28
- tsconfigRootDir: import.meta.dirname,
29
- },
30
- },
31
- })
32
- ```
33
-
34
- You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
35
-
36
- ```js
37
- // eslint.config.js
38
- import reactX from 'eslint-plugin-react-x'
39
- import reactDom from 'eslint-plugin-react-dom'
40
-
41
- export default tseslint.config({
42
- plugins: {
43
- // Add the react-x and react-dom plugins
44
- 'react-x': reactX,
45
- 'react-dom': reactDom,
46
- },
47
- rules: {
48
- // other rules...
49
- // Enable its recommended typescript rules
50
- ...reactX.configs['recommended-typescript'].rules,
51
- ...reactDom.configs.recommended.rules,
52
- },
53
- })
1
+ <hr>
2
+ <div align="center">
3
+ <h1 align="center">
4
+ useHotkeys(keys, callback)
5
+ </h1>
6
+ </div>
7
+
8
+ <p align="center">
9
+ <a href="https://bundlephobia.com/result?p=react-hotkeys-hook">
10
+ <img alt="Bundlephobia" src="https://img.shields.io/bundlephobia/minzip/react-hotkeys-hook?style=for-the-badge&labelColor=24292e">
11
+ </a>
12
+ <a aria-label="Types" href="https://www.npmjs.com/package/react-hotkeys-hook">
13
+ <img alt="Types" src="https://img.shields.io/npm/types/react-hotkeys-hook?style=for-the-badge&labelColor=24292e">
14
+ </a>
15
+ <a aria-label="NPM version" href="https://www.npmjs.com/package/react-hotkeys-hook">
16
+ <img alt="NPM Version" src="https://img.shields.io/npm/v/react-hotkeys-hook?style=for-the-badge&labelColor=24292e">
17
+ </a>
18
+ <a aria-label="License" href="https://jaredlunde.mit-license.org/">
19
+ <img alt="MIT License" src="https://img.shields.io/npm/l/react-hotkeys-hook?style=for-the-badge&labelColor=24292e">
20
+ </a>
21
+ </p>
22
+
23
+ <p align="center">
24
+ <a aria-label="Sponsored by Spaceteams" href="https://spaceteams.de">
25
+ <img alt="Sponsored by Spaceteams" src="https://raw.githubusercontent.com/spaceteams/badges/main/sponsored-by-spaceteams.svg">
26
+ </a>
27
+ </p>
28
+
54
29
  ```
30
+ npm i react-hotkeys-hook
31
+ ```
32
+
33
+ <p align="center">
34
+ A React hook for using keyboard shortcuts in components in a declarative way.
35
+ </p>
36
+
37
+ <hr>
38
+
39
+ ## Quick Start
40
+
41
+ The easiest way to use the hook.
42
+
43
+ ```jsx harmony
44
+ import { useHotkeys } from 'react-hotkeys-hook'
45
+
46
+ export const ExampleComponent = () => {
47
+ const [count, setCount] = useState(0)
48
+ useHotkeys('ctrl+k', () => setCount(count + 1), [count])
49
+
50
+ return (
51
+ <p>
52
+ Pressed {count} times.
53
+ </p>
54
+ )
55
+ }
56
+ ```
57
+
58
+ ### Scopes
59
+
60
+ Scopes allow you to group hotkeys together. You can use scopes to prevent hotkeys from colliding with each other.
61
+
62
+ ```jsx harmony
63
+ const App = () => {
64
+ return (
65
+ <HotkeysProvider initiallyActiveScopes={['settings']}>
66
+ <ExampleComponent />
67
+ </HotkeysProvider>
68
+ )
69
+ }
70
+
71
+ export const ExampleComponent = () => {
72
+ const [count, setCount] = useState(0)
73
+ useHotkeys('ctrl+k', () => setCount(prevCount => prevCount + 1), { scopes: ['settings'] })
74
+
75
+ return (
76
+ <p>
77
+ Pressed {count} times.
78
+ </p>
79
+ )
80
+ }
81
+ ```
82
+
83
+ #### Changing a scope's active state
84
+
85
+ You can change the active state of a scope using the `disableScope`, `enableScope` and `toggleScope` functions
86
+ returned by the `useHotkeysContext()` hook. Note that you have to have your app wrapped in a `<HotkeysProvider>` component.
87
+
88
+ ```jsx harmony
89
+ const App = () => {
90
+ return (
91
+ <HotkeysProvider initiallyActiveScopes={['settings']}>
92
+ <ExampleComponent />
93
+ </HotkeysProvider>
94
+ )
95
+ }
96
+
97
+ export const ExampleComponent = () => {
98
+ const { toggleScope } = useHotkeysContext()
99
+
100
+ return (
101
+ <button onClick={() => toggleScope('settings')}>
102
+ Change scope active state
103
+ </button>
104
+ )
105
+ }
106
+ ```
107
+
108
+ ### Focus trap
109
+
110
+ This will only trigger the hotkey if the component is focused.
111
+
112
+ ```tsx harmony
113
+ export const ExampleComponent = () => {
114
+ const [count, setCount] = useState(0)
115
+ const ref = useHotkeys<HTMLParagraphElement>('ctrl+k', () => setCount(prevCount => prevCount + 1))
116
+
117
+ return (
118
+ <p tabIndex={-1} ref={ref}>
119
+ Pressed {count} times.
120
+ </p>
121
+ )
122
+ }
123
+ ```
124
+
125
+ ## Documentation & Live Examples
126
+
127
+ * [Quick Start](https://react-hotkeys-hook.vercel.app/docs/intro)
128
+ * [Documentation](https://react-hotkeys-hook.vercel.app/docs/documentation/installation)
129
+ * [API](https://react-hotkeys-hook.vercel.app/docs/api/use-hotkeys)
130
+
131
+ ## API
132
+
133
+ ### useHotkeys(keys, callback)
134
+
135
+ ```typescript
136
+ useHotkeys(keys: string | string[], callback: (event: KeyboardEvent, handler: HotkeysEvent) => void, options: Options = {}, deps: DependencyList = [])
137
+ ```
138
+
139
+ | Parameter | Type | Required? | Default value | Description |
140
+ |---------------|---------------------------------------------------------|-----------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
141
+ | `keys` | `string` or `string[]` | required | - | set the hotkeys you want the hook to listen to. You can use single or multiple keys, modifier combinations, etc. This will either be a string or an array of strings. To separate multiple keys, use a comma. This split key value can be overridden with the `splitKey` option. |
142
+ | `callback` | `(event: KeyboardEvent, handler: HotkeysEvent) => void` | required | - | This is the callback function that will be called when the hotkey is pressed. The callback will receive the browsers native `KeyboardEvent` and the libraries `HotkeysEvent`. |
143
+ | `options` | `Options` | optional | `{}` | Object to modify the behavior of the hook. Default options are given below. |
144
+ | `dependencies` | `DependencyList` | optional | `[]` | The given callback will always be memoised inside the hook. So if you reference any outside variables, you need to set them here for the callback to get updated (Much like `useCallback` works in React). |
145
+
146
+ ### Options
147
+
148
+ All options are optional and have a default value which you can override to change the behavior of the hook.
149
+
150
+ | Option | Type | Default value | Description |
151
+ |--------------------------|--------------------------------------------------------------------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
152
+ | `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 not registered if a focus focuses on an input field. This will prevent accidental triggering of hotkeys when the user is typing. If you want to enable hotkeys, use this option. Setting it to true will enable on all form tags, otherwise you can give an array of form tags to enable the hotkey on (possible options are: `['input', 'textarea', 'select']`) |
154
+ | `enableOnContentEditable` | `boolean` | `false` | Set this option to enable hotkeys on tags that have set the `contentEditable` prop to `true` |
155
+ | `combinationKey` | `string` | `+` | Character to indicate keystrokes like `shift+c`. You might want to change this if you want to listen to the `+` character like `ctrl-+`. |
156
+ | `splitKey` | `string` | `,` | Character to separate different keystrokes like `ctrl+a, ctrl+b`. |
157
+ | `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` | Determines whether to listen to the browsers `keyup` event for triggering the callback. |
159
+ | `keydown` | `boolean` | `true` | Determines whether to listen to the browsers `keydown` event for triggering the callback. If you set both `keyup`and `keydown` to true, the callback will trigger on both events. |
160
+ | `preventDefault` | `boolean` or `(keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => boolean` | `false` | Set this to a `true` if you want the hook to prevent the browsers default behavior on certain keystrokes like `meta+s` to save a page. NOTE: Certain keystrokes are not preventable, like `meta+w` to close a tab in chrome. |
161
+ | `description` | `string` | `undefined` | Use this option to describe what the hotkey does. this is helpful if you want to display a list of active hotkeys to the user. |
162
+
163
+
164
+ #### Overloads
165
+
166
+ The hooks call signature is very flexible. For example if you don't need to set any special options you can use the dependency
167
+ array as your third parameter:
168
+
169
+ `useHotkeys('ctrl+k', () => console.log(counter + 1), [counter])`
170
+
171
+ ### `isHotkeyPressed(keys: string | string[], splitKey?: string = ',')`
172
+
173
+ This function allows us to check if the user is currently pressing down a key.
174
+
175
+ ```ts
176
+ import { isHotkeyPressed } from 'react-hotkeys-hook'
177
+
178
+ isHotkeyPressed('esc') // Returns true if Escape key is pressed down.
179
+ ```
180
+
181
+ You can also check for multiple keys at the same time:
182
+
183
+ ```ts
184
+ isHotkeyPressed(['esc', 'ctrl+s']) // Returns true if Escape or Ctrl+S are pressed down.
185
+ ```
186
+
187
+ ## Support
188
+
189
+ * Ask your question in the [Github Discussions]([Support](https://github.com/JohannesKlauss/react-hotkeys-hook/discussions))
190
+ * Ask your question on [StackOverflow](https://stackoverflow.com/search?page=1&tab=Relevance&q=react-hotkeys-hook)
191
+
192
+ ## Found an issue or have a feature request?
193
+
194
+ Open up an [issue](https://github.com/JohannesKlauss/react-hotkeys-hook/issues/new)
195
+ or [pull request](https://github.com/JohannesKlauss/react-hotkeys-hook/compare) and participate.
196
+
197
+ ## Local Development
198
+
199
+ Checkout this repo, run `yarn` or `npm i` and then run the `test` script to test the behavior of the hook.
200
+
201
+ ## Contributing
202
+ Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
203
+
204
+ 1. Fork the Project
205
+ 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
206
+ 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
207
+ 4. Push to the Branch (`git push origin feature/AmazingFeature`)
208
+ 5. Open a Pull Request
209
+
210
+ ## License
211
+ Distributed under the MIT License. See `LICENSE` for more information.
212
+
213
+ ## Contact
214
+
215
+ Johannes Klauss - [@JohannesKlauss](https://github.com/JohannesKlauss) - klauss.johannes@gmail.com
216
+
217
+ Project Link: [https://github.com/JohannesKlauss/react-hotkeys-hook](https://github.com/JohannesKlauss/react-hotkeys-hook)
218
+
219
+ ## Contributors
220
+
221
+ <a href="https://github.com/johannesklauss/react-hotkeys-hook/graphs/contributors">
222
+ <img src="https://contrib.rocks/image?repo=johannesklauss/react-hotkeys-hook" />
223
+ </a>
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createContext as T, useContext as M, useState as A, useCallback as k, useRef as S, useLayoutEffect as z, useEffect as J } from "react";
1
+ import { createContext as T, useContext as M, useState as A, useCallback as w, useRef as S, useLayoutEffect as z, useEffect as J } from "react";
2
2
  import { jsx as b } from "react/jsx-runtime";
3
3
  const j = ["shift", "alt", "meta", "mod", "ctrl", "control"], Q = {
4
4
  esc: "escape",
@@ -24,27 +24,27 @@ function K(e) {
24
24
  function D(e) {
25
25
  return j.includes(e);
26
26
  }
27
- function H(e, n = ",") {
28
- return e.toLowerCase().split(n);
27
+ function H(e, r = ",") {
28
+ return e.toLowerCase().split(r);
29
29
  }
30
- function P(e, n = "+", r = ">", i = !1, u, f) {
31
- let o = [], y = !1;
32
- e = e.trim(), e.includes(r) ? (y = !0, o = e.toLocaleLowerCase().split(r).map((d) => K(d))) : o = e.toLocaleLowerCase().split(n).map((d) => K(d));
33
- const c = {
34
- alt: o.includes("alt"),
35
- ctrl: o.includes("ctrl") || o.includes("control"),
36
- shift: o.includes("shift"),
37
- meta: o.includes("meta"),
38
- mod: o.includes("mod"),
30
+ function P(e, r = "+", o = ">", i = !1, c, a) {
31
+ let n = [], y = !1;
32
+ e = e.trim(), e.includes(o) ? (y = !0, n = e.toLocaleLowerCase().split(o).map((f) => K(f))) : n = e.toLocaleLowerCase().split(r).map((f) => K(f));
33
+ const u = {
34
+ alt: n.includes("alt"),
35
+ ctrl: n.includes("ctrl") || n.includes("control"),
36
+ shift: n.includes("shift"),
37
+ meta: n.includes("meta"),
38
+ mod: n.includes("mod"),
39
39
  useKey: i
40
- }, m = o.filter((d) => !j.includes(d));
40
+ }, l = n.filter((f) => !j.includes(f));
41
41
  return {
42
- ...c,
43
- keys: m,
44
- description: u,
42
+ ...u,
43
+ keys: l,
44
+ description: c,
45
45
  isSequence: y,
46
46
  hotkey: e,
47
- metadata: f
47
+ metadata: a
48
48
  };
49
49
  }
50
50
  typeof document < "u" && (document.addEventListener("keydown", (e) => {
@@ -62,28 +62,28 @@ const L = /* @__PURE__ */ new Set();
62
62
  function R(e) {
63
63
  return Array.isArray(e);
64
64
  }
65
- function U(e, n = ",") {
66
- return (R(e) ? e : e.split(n)).every((i) => L.has(i.trim().toLowerCase()));
65
+ function U(e, r = ",") {
66
+ return (R(e) ? e : e.split(r)).every((i) => L.has(i.trim().toLowerCase()));
67
67
  }
68
68
  function _(e) {
69
- const n = Array.isArray(e) ? e : [e];
70
- L.has("meta") && L.forEach((r) => {
71
- D(r) || L.delete(r.toLowerCase());
72
- }), n.forEach((r) => {
73
- L.add(r.toLowerCase());
69
+ const r = Array.isArray(e) ? e : [e];
70
+ L.has("meta") && L.forEach((o) => {
71
+ D(o) || L.delete(o.toLowerCase());
72
+ }), r.forEach((o) => {
73
+ L.add(o.toLowerCase());
74
74
  });
75
75
  }
76
76
  function I(e) {
77
- const n = Array.isArray(e) ? e : [e];
78
- e === "meta" ? L.clear() : n.forEach((r) => {
79
- L.delete(r.toLowerCase());
77
+ const r = Array.isArray(e) ? e : [e];
78
+ e === "meta" ? L.clear() : r.forEach((o) => {
79
+ L.delete(o.toLowerCase());
80
80
  });
81
81
  }
82
- function V(e, n, r) {
83
- (typeof r == "function" && r(e, n) || r === !0) && e.preventDefault();
82
+ function V(e, r, o) {
83
+ (typeof o == "function" && o(e, r) || o === !0) && e.preventDefault();
84
84
  }
85
- function X(e, n, r) {
86
- return typeof r == "function" ? r(e, n) : r === !0 || r === void 0;
85
+ function X(e, r, o) {
86
+ return typeof o == "function" ? o(e, r) : o === !0 || o === void 0;
87
87
  }
88
88
  const Y = [
89
89
  "input",
@@ -102,50 +102,40 @@ const Y = [
102
102
  function Z(e) {
103
103
  return F(e, Y);
104
104
  }
105
- function F(e, n = !1) {
106
- const { target: r, composed: i } = e;
107
- let u, f;
108
- return ee(r) && i ? (u = e.composedPath()[0] && e.composedPath()[0].tagName, f = e.composedPath()[0] && e.composedPath()[0].role) : (u = r && r.tagName, f = r && r.role), R(n) ? !!(u && n && n.some((o) => o.toLowerCase() === u.toLowerCase() || o === f)) : !!(u && n && n);
105
+ function F(e, r = !1) {
106
+ const { target: o, composed: i } = e;
107
+ let c, a;
108
+ return ee(o) && i ? (c = e.composedPath()[0] && e.composedPath()[0].tagName, a = e.composedPath()[0] && e.composedPath()[0].role) : (c = o && o.tagName, a = o && o.role), R(r) ? !!(c && r && r.some((n) => n.toLowerCase() === c.toLowerCase() || n === a)) : !!(c && r && r);
109
109
  }
110
110
  function ee(e) {
111
111
  return !!e.tagName && !e.tagName.startsWith("-") && e.tagName.includes("-");
112
112
  }
113
- function te(e, n) {
114
- return e.length === 0 && n ? !1 : n ? e.some((r) => n.includes(r)) || e.includes("*") : !0;
113
+ function te(e, r) {
114
+ return e.length === 0 && r ? !1 : r ? e.some((o) => r.includes(o)) || e.includes("*") : !0;
115
115
  }
116
- const re = (e, n, r = !1) => {
117
- const { alt: i, meta: u, mod: f, shift: o, ctrl: y, keys: c, useKey: m } = n, { code: d, key: t, ctrlKey: a, metaKey: l, shiftKey: h, altKey: w } = e, p = K(d);
118
- if (m) {
119
- if (c?.length === 1 && c.includes(t.toLowerCase())) {
120
- if (!r) {
121
- if (i !== w || o !== h) return !1;
122
- if (f) {
123
- if (!l && !a) return !1;
124
- } else if (u !== l || y !== a) return !1;
125
- }
126
- return !0;
127
- }
128
- return !1;
129
- }
130
- if (!c?.includes(p) && !["ctrl", "control", "unknown", "meta", "alt", "shift", "os"].includes(p))
116
+ const re = (e, r, o = !1) => {
117
+ const { alt: i, meta: c, mod: a, shift: n, ctrl: y, keys: u, useKey: l } = r, { code: f, key: t, ctrlKey: d, metaKey: m, shiftKey: g, altKey: k } = e, p = K(f);
118
+ if (l && u?.length === 1 && u.includes(t.toLowerCase()))
119
+ return !0;
120
+ if (!u?.includes(p) && !["ctrl", "control", "unknown", "meta", "alt", "shift", "os"].includes(p))
131
121
  return !1;
132
- if (!r) {
133
- if (i !== w && p !== "alt" || o !== h && p !== "shift")
122
+ if (!o) {
123
+ if (i !== k && p !== "alt" || n !== g && p !== "shift")
134
124
  return !1;
135
- if (f) {
136
- if (!l && !a)
125
+ if (a) {
126
+ if (!m && !d)
137
127
  return !1;
138
- } else if (u !== l && p !== "meta" && p !== "os" || y !== a && p !== "ctrl" && p !== "control")
128
+ } else if (c !== m && p !== "meta" && p !== "os" || y !== d && p !== "ctrl" && p !== "control")
139
129
  return !1;
140
130
  }
141
- return c && c.length === 1 && c.includes(p) ? !0 : c && c.length > 0 ? c.includes(p) ? U(c) : !1 : !c || c.length === 0;
142
- }, $ = T(void 0), ne = () => M($);
143
- function oe({ addHotkey: e, removeHotkey: n, children: r }) {
144
- return /* @__PURE__ */ b($.Provider, { value: { addHotkey: e, removeHotkey: n }, children: r });
131
+ return u && u.length === 1 && u.includes(p) ? !0 : u && u.length > 0 ? u.includes(p) ? U(u) : !1 : !u || u.length === 0;
132
+ }, $ = T(void 0), oe = () => M($);
133
+ function ne({ addHotkey: e, removeHotkey: r, children: o }) {
134
+ return /* @__PURE__ */ b($.Provider, { value: { addHotkey: e, removeHotkey: r }, children: o });
145
135
  }
146
- function x(e, n) {
147
- return e && n && typeof e == "object" && typeof n == "object" ? Object.keys(e).length === Object.keys(n).length && // @ts-expect-error TS7053
148
- Object.keys(e).reduce((r, i) => r && x(e[i], n[i]), !0) : e === n;
136
+ function x(e, r) {
137
+ return e && r && typeof e == "object" && typeof r == "object" ? Object.keys(e).length === Object.keys(r).length && // @ts-expect-error TS7053
138
+ Object.keys(e).reduce((o, i) => o && x(e[i], r[i]), !0) : e === r;
149
139
  }
150
140
  const W = T({
151
141
  hotkeys: [],
@@ -157,46 +147,46 @@ const W = T({
157
147
  },
158
148
  disableScope: () => {
159
149
  }
160
- }), se = () => M(W), fe = ({ initiallyActiveScopes: e = ["*"], children: n }) => {
161
- const [r, i] = A(e), [u, f] = A([]), o = k((t) => {
162
- i((a) => a.includes("*") ? [t] : Array.from(/* @__PURE__ */ new Set([...a, t])));
163
- }, []), y = k((t) => {
164
- i((a) => a.filter((l) => l !== t));
165
- }, []), c = k((t) => {
166
- i((a) => a.includes(t) ? a.filter((l) => l !== t) : a.includes("*") ? [t] : Array.from(/* @__PURE__ */ new Set([...a, t])));
167
- }, []), m = k((t) => {
168
- f((a) => [...a, t]);
169
- }, []), d = k((t) => {
170
- f((a) => a.filter((l) => !x(l, t)));
150
+ }), se = () => M(W), de = ({ initiallyActiveScopes: e = ["*"], children: r }) => {
151
+ const [o, i] = A(e), [c, a] = A([]), n = w((t) => {
152
+ i((d) => d.includes("*") ? [t] : Array.from(/* @__PURE__ */ new Set([...d, t])));
153
+ }, []), y = w((t) => {
154
+ i((d) => d.filter((m) => m !== t));
155
+ }, []), u = w((t) => {
156
+ i((d) => d.includes(t) ? d.filter((m) => m !== t) : d.includes("*") ? [t] : Array.from(/* @__PURE__ */ new Set([...d, t])));
157
+ }, []), l = w((t) => {
158
+ a((d) => [...d, t]);
159
+ }, []), f = w((t) => {
160
+ a((d) => d.filter((m) => !x(m, t)));
171
161
  }, []);
172
162
  return /* @__PURE__ */ b(
173
163
  W.Provider,
174
164
  {
175
- value: { activeScopes: r, hotkeys: u, enableScope: o, disableScope: y, toggleScope: c },
176
- children: /* @__PURE__ */ b(oe, { addHotkey: m, removeHotkey: d, children: n })
165
+ value: { activeScopes: o, hotkeys: c, enableScope: n, disableScope: y, toggleScope: u },
166
+ children: /* @__PURE__ */ b(ne, { addHotkey: l, removeHotkey: f, children: r })
177
167
  }
178
168
  );
179
169
  };
180
170
  function ie(e) {
181
- const n = S(void 0);
182
- return x(n.current, e) || (n.current = e), n.current;
171
+ const r = S(void 0);
172
+ return x(r.current, e) || (r.current = e), r.current;
183
173
  }
184
174
  const N = (e) => {
185
175
  e.stopPropagation(), e.preventDefault(), e.stopImmediatePropagation();
186
- }, ue = typeof window < "u" ? z : J;
187
- function de(e, n, r, i) {
188
- const u = S(null), f = S(!1), o = Array.isArray(r) ? Array.isArray(i) ? void 0 : i : r, y = R(e) ? e.join(o?.delimiter) : e, c = Array.isArray(r) ? r : Array.isArray(i) ? i : void 0, m = k(n, c ?? []), d = S(m);
189
- c ? d.current = m : d.current = n;
190
- const t = ie(o), { activeScopes: a } = se(), l = ne();
191
- return ue(() => {
192
- if (t?.enabled === !1 || !te(a, t?.scopes))
176
+ }, ce = typeof window < "u" ? z : J;
177
+ function fe(e, r, o, i) {
178
+ const c = S(null), a = S(!1), n = Array.isArray(o) ? Array.isArray(i) ? void 0 : i : o, y = R(e) ? e.join(n?.delimiter) : e, u = Array.isArray(o) ? o : Array.isArray(i) ? i : void 0, l = w(r, u ?? []), f = S(l);
179
+ u ? f.current = l : f.current = r;
180
+ const t = ie(n), { activeScopes: d } = se(), m = oe();
181
+ return ce(() => {
182
+ if (t?.enabled === !1 || !te(d, t?.scopes))
193
183
  return;
194
- let h = [], w;
184
+ let g = [], k;
195
185
  const p = (s, B = !1) => {
196
186
  if (!(Z(s) && !F(s, t?.enableOnFormTags))) {
197
- if (u.current !== null) {
198
- const v = u.current.getRootNode();
199
- if ((v instanceof Document || v instanceof ShadowRoot) && v.activeElement !== u.current && !u.current.contains(v.activeElement)) {
187
+ if (c.current !== null) {
188
+ const v = c.current.getRootNode();
189
+ if ((v instanceof Document || v instanceof ShadowRoot) && v.activeElement !== c.current && !c.current.contains(v.activeElement)) {
200
190
  N(s);
201
191
  return;
202
192
  }
@@ -208,7 +198,7 @@ function de(e, n, r, i) {
208
198
  );
209
199
  return;
210
200
  }
211
- const g = P(
201
+ const h = P(
212
202
  v,
213
203
  t?.splitKey,
214
204
  t?.sequenceSplitKey,
@@ -216,38 +206,38 @@ function de(e, n, r, i) {
216
206
  t?.description,
217
207
  t?.metadata
218
208
  );
219
- if (g.isSequence) {
220
- w = setTimeout(() => {
221
- h = [];
209
+ if (h.isSequence) {
210
+ k = setTimeout(() => {
211
+ g = [];
222
212
  }, t?.sequenceTimeoutMs ?? 1e3);
223
- const C = g.useKey ? s.key : K(s.code);
213
+ const C = h.useKey ? s.key : K(s.code);
224
214
  if (D(C.toLowerCase()))
225
215
  return;
226
- h.push(C);
227
- const G = g.keys?.[h.length - 1];
216
+ g.push(C);
217
+ const G = h.keys?.[g.length - 1];
228
218
  if (C !== G) {
229
- h = [], w && clearTimeout(w);
219
+ g = [], k && clearTimeout(k);
230
220
  return;
231
221
  }
232
- h.length === g.keys?.length && (d.current(s, g), w && clearTimeout(w), h = []);
233
- } else if (re(s, g, t?.ignoreModifiers) || g.keys?.includes("*")) {
234
- if (t?.ignoreEventWhen?.(s) || B && f.current)
222
+ g.length === h.keys?.length && (f.current(s, h), k && clearTimeout(k), g = []);
223
+ } else if (re(s, h, t?.ignoreModifiers) || h.keys?.includes("*")) {
224
+ if (t?.ignoreEventWhen?.(s) || B && a.current)
235
225
  return;
236
- if (V(s, g, t?.preventDefault), !X(s, g, t?.enabled)) {
226
+ if (V(s, h, t?.preventDefault), !X(s, h, t?.enabled)) {
237
227
  N(s);
238
228
  return;
239
229
  }
240
- d.current(s, g), B || (f.current = !0);
230
+ f.current(s, h), B || (a.current = !0);
241
231
  }
242
232
  });
243
233
  }
244
234
  }, O = (s) => {
245
235
  s.code !== void 0 && (_(K(s.code)), (t?.keydown === void 0 && t?.keyup !== !0 || t?.keydown) && p(s));
246
236
  }, q = (s) => {
247
- s.code !== void 0 && (I(K(s.code)), f.current = !1, t?.keyup && p(s, !0));
248
- }, E = u.current || o?.document || document;
249
- return E.addEventListener("keyup", q, o?.eventListenerOptions), E.addEventListener("keydown", O, o?.eventListenerOptions), l && H(y, t?.delimiter).forEach((s) => {
250
- l.addHotkey(
237
+ s.code !== void 0 && (I(K(s.code)), a.current = !1, t?.keyup && p(s, !0));
238
+ }, E = c.current || n?.document || document;
239
+ return E.addEventListener("keyup", q, n?.eventListenerOptions), E.addEventListener("keydown", O, n?.eventListenerOptions), m && H(y, t?.delimiter).forEach((s) => {
240
+ m.addHotkey(
251
241
  P(
252
242
  s,
253
243
  t?.splitKey,
@@ -258,8 +248,8 @@ function de(e, n, r, i) {
258
248
  )
259
249
  );
260
250
  }), () => {
261
- E.removeEventListener("keyup", q, o?.eventListenerOptions), E.removeEventListener("keydown", O, o?.eventListenerOptions), l && H(y, t?.delimiter).forEach((s) => {
262
- l.removeHotkey(
251
+ E.removeEventListener("keyup", q, n?.eventListenerOptions), E.removeEventListener("keydown", O, n?.eventListenerOptions), m && H(y, t?.delimiter).forEach((s) => {
252
+ m.removeHotkey(
263
253
  P(
264
254
  s,
265
255
  t?.splitKey,
@@ -269,32 +259,32 @@ function de(e, n, r, i) {
269
259
  t?.metadata
270
260
  )
271
261
  );
272
- }), h = [], w && clearTimeout(w);
262
+ }), g = [], k && clearTimeout(k);
273
263
  };
274
- }, [y, t, a]), u;
264
+ }, [y, t, d]), c;
275
265
  }
276
266
  function le(e = !1) {
277
- const [n, r] = A(/* @__PURE__ */ new Set()), [i, u] = A(!1), f = k(
278
- (m) => {
279
- m.code !== void 0 && (m.preventDefault(), m.stopPropagation(), r((d) => {
280
- const t = new Set(d);
281
- return t.add(K(e ? m.key : m.code)), t;
267
+ const [r, o] = A(/* @__PURE__ */ new Set()), [i, c] = A(!1), a = w(
268
+ (l) => {
269
+ l.code !== void 0 && (l.preventDefault(), l.stopPropagation(), o((f) => {
270
+ const t = new Set(f);
271
+ return t.add(K(e ? l.key : l.code)), t;
282
272
  }));
283
273
  },
284
274
  [e]
285
- ), o = k(() => {
286
- typeof document < "u" && (document.removeEventListener("keydown", f), u(!1));
287
- }, [f]), y = k(() => {
288
- r(/* @__PURE__ */ new Set()), typeof document < "u" && (o(), document.addEventListener("keydown", f), u(!0));
289
- }, [f, o]), c = k(() => {
290
- r(/* @__PURE__ */ new Set());
275
+ ), n = w(() => {
276
+ typeof document < "u" && (document.removeEventListener("keydown", a), c(!1));
277
+ }, [a]), y = w(() => {
278
+ o(/* @__PURE__ */ new Set()), typeof document < "u" && (n(), document.addEventListener("keydown", a), c(!0));
279
+ }, [a, n]), u = w(() => {
280
+ o(/* @__PURE__ */ new Set());
291
281
  }, []);
292
- return [n, { start: y, stop: o, resetKeys: c, isRecording: i }];
282
+ return [r, { start: y, stop: n, resetKeys: u, isRecording: i }];
293
283
  }
294
284
  export {
295
- fe as HotkeysProvider,
285
+ de as HotkeysProvider,
296
286
  U as isHotkeyPressed,
297
- de as useHotkeys,
287
+ fe as useHotkeys,
298
288
  se as useHotkeysContext,
299
289
  le as useRecordHotkeys
300
290
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-hotkeys-hook",
3
- "version": "5.2.2",
3
+ "version": "5.2.4",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite",