@solid-primitives/keyboard 1.2.8 → 1.3.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/README.md CHANGED
@@ -11,12 +11,12 @@
11
11
 
12
12
  A library of reactive promitives helping handling user's keyboard input.
13
13
 
14
- - [`useKeyDownEvent`](#useKeyDownEvent) — Provides a signal with the last keydown event.
15
- - [`useKeyDownList`](#useKeyDownList) — Provides a signal with the list of currently held keys
16
- - [`useCurrentlyHeldKey`](#useCurrentlyHeldKey) — Provides a signal with the currently held single key.
17
- - [`useKeyDownSequence`](#useKeyDownSequence) — Provides a signal with a sequence of currently held keys, as they were pressed down and up.
18
- - [`createKeyHold`](#createKeyHold) — Provides a signal indicating if provided key is currently being held down.
19
- - [`createShortcut`](#createShortcut) — Creates a keyboard shotcut observer.
14
+ - [`useKeyDownEvent`](#usekeydownevent) — Provides a signal with the last keydown event.
15
+ - [`useKeyDownList`](#usekeydownlist) — Provides a signal with the list of currently held keys
16
+ - [`useCurrentlyHeldKey`](#usecurrentlyheldkey) — Provides a signal with the currently held single key.
17
+ - [`useKeyDownSequence`](#usekeydownsequence) — Provides a signal with a sequence of currently held keys, as they were pressed down and up.
18
+ - [`createKeyHold`](#createkeyhold) — Provides a signal indicating if provided key is currently being held down.
19
+ - [`createShortcut`](#createshortcut) — Creates a keyboard shotcut observer.
20
20
 
21
21
  ## Installation
22
22
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import { Accessor } from 'solid-js';
2
-
3
- type ModifierKey = "Alt" | "Control" | "Meta" | "Shift";
4
- type KbdKey = ModifierKey | (string & {});
1
+ import { Accessor } from "solid-js";
2
+ export type ModifierKey = "Alt" | "Control" | "Meta" | "Shift";
3
+ export type KbdKey = ModifierKey | (string & {});
5
4
  /**
6
5
  * Provides a signal with the last keydown event.
7
6
  *
@@ -30,7 +29,7 @@ type KbdKey = ModifierKey | (string & {});
30
29
  * })
31
30
  * ```
32
31
  */
33
- declare const useKeyDownEvent: () => Accessor<KeyboardEvent | null>;
32
+ export declare const useKeyDownEvent: () => Accessor<KeyboardEvent | null>;
34
33
  /**
35
34
  * Provides a signal with the list of currently held keys, ordered from least recent to most recent.
36
35
  *
@@ -52,7 +51,7 @@ declare const useKeyDownEvent: () => Accessor<KeyboardEvent | null>;
52
51
  * })
53
52
  * ```
54
53
  */
55
- declare const useKeyDownList: () => Accessor<string[]>;
54
+ export declare const useKeyDownList: () => Accessor<string[]>;
56
55
  /**
57
56
  * Provides a signal with the currently held single key. Pressing any other key at the same time will reset the signal to `null`.
58
57
  *
@@ -73,7 +72,7 @@ declare const useKeyDownList: () => Accessor<string[]>;
73
72
  * })
74
73
  * ```
75
74
  */
76
- declare const useCurrentlyHeldKey: () => Accessor<string | null>;
75
+ export declare const useCurrentlyHeldKey: () => Accessor<string | null>;
77
76
  /**
78
77
  * Provides a signal with a sequence of currently held keys, as they were pressed down and up.
79
78
  *
@@ -95,7 +94,7 @@ declare const useCurrentlyHeldKey: () => Accessor<string | null>;
95
94
  * })
96
95
  * ```
97
96
  */
98
- declare const useKeyDownSequence: () => Accessor<string[][]>;
97
+ export declare const useKeyDownSequence: () => Accessor<string[][]>;
99
98
  /**
100
99
  * Provides a `boolean` signal indicating if provided {@link key} is currently being held down.
101
100
  * Holding multiple keys at the same time will return `false` — holding only the specified one will return `true`.
@@ -118,7 +117,7 @@ declare const useKeyDownSequence: () => Accessor<string[][]>;
118
117
  * })
119
118
  * ```
120
119
  */
121
- declare function createKeyHold(key: KbdKey, options?: {
120
+ export declare function createKeyHold(key: KbdKey, options?: {
122
121
  preventDefault?: boolean;
123
122
  }): Accessor<boolean>;
124
123
  /**
@@ -139,9 +138,7 @@ declare function createKeyHold(key: KbdKey, options?: {
139
138
  * });
140
139
  * ```
141
140
  */
142
- declare function createShortcut(keys: KbdKey[], callback: (event: KeyboardEvent | null) => void, options?: {
141
+ export declare function createShortcut(keys: KbdKey[], callback: (event: KeyboardEvent | null) => void, options?: {
143
142
  preventDefault?: boolean;
144
143
  requireReset?: boolean;
145
144
  }): void;
146
-
147
- export { KbdKey, ModifierKey, createKeyHold, createShortcut, useCurrentlyHeldKey, useKeyDownEvent, useKeyDownList, useKeyDownSequence };
package/dist/index.js CHANGED
@@ -1,165 +1,303 @@
1
- import { makeEventListener } from '@solid-primitives/event-listener';
2
- import { createSingletonRoot } from '@solid-primitives/rootless';
3
- import { arrayEquals } from '@solid-primitives/utils';
4
- import { createSignal, untrack, createMemo, createEffect, on } from 'solid-js';
5
- import { isServer } from 'solid-js/web';
6
-
7
- // src/index.ts
1
+ import { makeEventListener } from "@solid-primitives/event-listener";
2
+ import { createSingletonRoot } from "@solid-primitives/rootless";
3
+ import { arrayEquals } from "@solid-primitives/utils";
4
+ import { createEffect, createMemo, createSignal, on, untrack } from "solid-js";
5
+ import { isServer } from "solid-js/web";
8
6
  function equalsKeyHoldSequence(sequence, model) {
9
- for (let i = sequence.length - 1; i >= 0; i--) {
10
- const _model = model.slice(0, i + 1);
11
- if (!arrayEquals(sequence[i], _model))
12
- return false;
13
- }
14
- return true;
7
+ for (let i = sequence.length - 1; i >= 0; i--) {
8
+ const _model = model.slice(0, i + 1);
9
+ if (!arrayEquals(sequence[i], _model))
10
+ return false;
11
+ }
12
+ return true;
15
13
  }
16
- var useKeyDownEvent = /* @__PURE__ */ createSingletonRoot(
17
- () => {
14
+ /**
15
+ * Provides a signal with the last keydown event.
16
+ *
17
+ * The signal is `null` initially, and is reset to that after a timeout.
18
+ *
19
+ * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#useKeyDownEvent
20
+ *
21
+ * @returns
22
+ * Returns a signal of the last keydown event
23
+ * ```ts
24
+ * Accessor<KeyboardEvent | null>
25
+ * ```
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const event = useKeyDownEvent();
30
+ *
31
+ * createEffect(() => {
32
+ * const e = event();
33
+ * console.log(e) // => KeyboardEvent | null
34
+ *
35
+ * if (e) {
36
+ * console.log(e.key) // => "Q" | "ALT" | ... or null
37
+ * e.preventDefault(); // prevent default behavior or last keydown event
38
+ * }
39
+ * })
40
+ * ```
41
+ */
42
+ export const useKeyDownEvent = /*#__PURE__*/ createSingletonRoot(() => {
18
43
  if (isServer) {
19
- return () => null;
44
+ return () => null;
20
45
  }
21
46
  const [event, setEvent] = createSignal(null);
22
- makeEventListener(window, "keydown", (e) => {
23
- setEvent(e);
24
- setTimeout(() => setEvent(null));
47
+ makeEventListener(window, "keydown", e => {
48
+ setEvent(e);
49
+ setTimeout(() => setEvent(null));
25
50
  });
26
51
  return event;
27
- }
28
- );
29
- var useKeyDownList = /* @__PURE__ */ createSingletonRoot(() => {
30
- if (isServer) {
31
- const keys = () => [];
32
- keys[0] = keys;
33
- keys[1] = { event: () => null };
34
- keys[Symbol.iterator] = function* () {
35
- yield keys[0];
36
- yield keys[1];
37
- };
38
- return keys;
39
- }
40
- const [pressedKeys, setPressedKeys] = createSignal([]), reset = () => setPressedKeys([]), event = useKeyDownEvent();
41
- makeEventListener(window, "keydown", (e) => {
42
- if (e.repeat || typeof e.key !== "string")
43
- return;
44
- const key = e.key.toUpperCase(), currentKeys = pressedKeys();
45
- if (currentKeys.includes(key))
46
- return;
47
- const keys = [...currentKeys, key];
48
- if (currentKeys.length === 0 && key !== "ALT" && key !== "CONTROL" && key !== "META" && key !== "SHIFT") {
49
- if (e.shiftKey)
50
- keys.unshift("SHIFT");
51
- if (e.altKey)
52
- keys.unshift("ALT");
53
- if (e.ctrlKey)
54
- keys.unshift("CONTROL");
55
- if (e.metaKey)
56
- keys.unshift("META");
52
+ });
53
+ /**
54
+ * Provides a signal with the list of currently held keys, ordered from least recent to most recent.
55
+ *
56
+ * This is a [singleton root primitive](https://github.com/solidjs-community/solid-primitives/tree/main/packages/rootless#createSingletonRoot). *(signals and event-listeners are reused across dependents)*
57
+ *
58
+ * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#useKeyDownList
59
+ *
60
+ * @returns
61
+ * Returns a signal of a list of keys
62
+ * ```ts
63
+ * Accessor<string[]>
64
+ * ```
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * const keys = useKeyDownList();
69
+ * createEffect(() => {
70
+ * console.log(keys()) // => ["ALT", "CONTROL", "Q", "A"]
71
+ * })
72
+ * ```
73
+ */
74
+ export const useKeyDownList = /*#__PURE__*/ createSingletonRoot(() => {
75
+ if (isServer) {
76
+ const keys = () => [];
77
+ // this is for backwards compatibility
78
+ // TODO remove in the next major version
79
+ keys[0] = keys;
80
+ keys[1] = { event: () => null };
81
+ keys[Symbol.iterator] = function* () {
82
+ yield keys[0];
83
+ yield keys[1];
84
+ };
85
+ return keys;
57
86
  }
58
- setPressedKeys(keys);
59
- });
60
- makeEventListener(window, "keyup", (e) => {
61
- if (typeof e.key !== "string")
62
- return;
63
- const key = e.key.toUpperCase();
64
- setPressedKeys((prev) => prev.filter((_key) => _key !== key));
65
- });
66
- makeEventListener(window, "blur", reset);
67
- makeEventListener(window, "contextmenu", (e) => {
68
- e.defaultPrevented || reset();
69
- });
70
- pressedKeys[0] = pressedKeys;
71
- pressedKeys[1] = { event };
72
- pressedKeys[Symbol.iterator] = function* () {
73
- yield pressedKeys[0];
74
- yield pressedKeys[1];
75
- };
76
- return pressedKeys;
87
+ const [pressedKeys, setPressedKeys] = createSignal([]), reset = () => setPressedKeys([]), event = useKeyDownEvent();
88
+ makeEventListener(window, "keydown", e => {
89
+ // e.key may be undefined when used with <datalist> el
90
+ // gh issue: https://github.com/solidjs-community/solid-primitives/issues/246
91
+ if (e.repeat || typeof e.key !== "string")
92
+ return;
93
+ const key = e.key.toUpperCase(), currentKeys = pressedKeys();
94
+ if (currentKeys.includes(key))
95
+ return;
96
+ const keys = [...currentKeys, key];
97
+ // if the modifier is pressed before we start listening
98
+ // we should add it to the list
99
+ if (currentKeys.length === 0 &&
100
+ key !== "ALT" &&
101
+ key !== "CONTROL" &&
102
+ key !== "META" &&
103
+ key !== "SHIFT") {
104
+ if (e.shiftKey)
105
+ keys.unshift("SHIFT");
106
+ if (e.altKey)
107
+ keys.unshift("ALT");
108
+ if (e.ctrlKey)
109
+ keys.unshift("CONTROL");
110
+ if (e.metaKey)
111
+ keys.unshift("META");
112
+ }
113
+ setPressedKeys(keys);
114
+ });
115
+ makeEventListener(window, "keyup", e => {
116
+ if (typeof e.key !== "string")
117
+ return;
118
+ const key = e.key.toUpperCase();
119
+ setPressedKeys(prev => prev.filter(_key => _key !== key));
120
+ });
121
+ makeEventListener(window, "blur", reset);
122
+ makeEventListener(window, "contextmenu", e => {
123
+ e.defaultPrevented || reset();
124
+ });
125
+ // this is for backwards compatibility
126
+ // TODO remove in the next major version
127
+ pressedKeys[0] = pressedKeys;
128
+ pressedKeys[1] = { event };
129
+ pressedKeys[Symbol.iterator] = function* () {
130
+ yield pressedKeys[0];
131
+ yield pressedKeys[1];
132
+ };
133
+ return pressedKeys;
77
134
  });
78
- var useCurrentlyHeldKey = /* @__PURE__ */ createSingletonRoot(
79
- () => {
135
+ /**
136
+ * Provides a signal with the currently held single key. Pressing any other key at the same time will reset the signal to `null`.
137
+ *
138
+ * This is a [singleton root primitive](https://github.com/solidjs-community/solid-primitives/tree/main/packages/rootless#createSingletonRoot). *(signals and event-listeners are reused across dependents)*
139
+ *
140
+ * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#useCurrentlyHeldKey
141
+ *
142
+ * @returns
143
+ * ```ts
144
+ * Accessor<string | null>
145
+ * ```
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * const key = useCurrentlyHeldKey();
150
+ * createEffect(() => {
151
+ * console.log(key()) // => "Q" | "ALT" | ... or null
152
+ * })
153
+ * ```
154
+ */
155
+ export const useCurrentlyHeldKey = /*#__PURE__*/ createSingletonRoot(() => {
80
156
  if (isServer) {
81
- return () => null;
157
+ return () => null;
82
158
  }
83
159
  const keys = useKeyDownList();
84
160
  let prevKeys = untrack(keys);
85
161
  return createMemo(() => {
86
- const _keys = keys();
87
- const prev = prevKeys;
88
- prevKeys = _keys;
89
- if (prev.length === 0 && _keys.length === 1)
90
- return _keys[0];
91
- return null;
162
+ const _keys = keys();
163
+ const prev = prevKeys;
164
+ prevKeys = _keys;
165
+ if (prev.length === 0 && _keys.length === 1)
166
+ return _keys[0];
167
+ return null;
92
168
  });
93
- }
94
- );
95
- var useKeyDownSequence = /* @__PURE__ */ createSingletonRoot(() => {
96
- if (isServer) {
97
- return () => [];
98
- }
99
- const keys = useKeyDownList();
100
- return createMemo((prev) => {
101
- if (keys().length === 0)
102
- return [];
103
- return [...prev, keys()];
104
- }, []);
105
169
  });
106
- function createKeyHold(key, options = {}) {
107
- if (isServer) {
108
- return () => false;
109
- }
110
- key = key.toUpperCase();
111
- const { preventDefault = true } = options, event = useKeyDownEvent(), heldKey = useCurrentlyHeldKey();
112
- return createMemo(() => heldKey() === key && (preventDefault && event()?.preventDefault(), true));
113
- }
114
- function createShortcut(keys, callback, options = {}) {
115
- if (isServer || !keys.length) {
116
- return;
117
- }
118
- keys = keys.map((key) => key.toUpperCase());
119
- const { preventDefault = true } = options, event = useKeyDownEvent(), sequence = useKeyDownSequence();
120
- let reset = false;
121
- const handleSequenceWithReset = (sequence2) => {
122
- if (!sequence2.length)
123
- return reset = false;
124
- if (reset)
125
- return;
126
- const e = event();
127
- if (sequence2.length < keys.length) {
128
- if (equalsKeyHoldSequence(sequence2, keys.slice(0, sequence2.length))) {
129
- preventDefault && e && e.preventDefault();
130
- } else {
131
- reset = true;
132
- }
133
- } else {
134
- reset = true;
135
- if (equalsKeyHoldSequence(sequence2, keys)) {
136
- preventDefault && e && e.preventDefault();
137
- callback(e);
138
- }
170
+ /**
171
+ * Provides a signal with a sequence of currently held keys, as they were pressed down and up.
172
+ *
173
+ * This is a [singleton root primitive](https://github.com/solidjs-community/solid-primitives/tree/main/packages/rootless#createSingletonRoot). *(signals and event-listeners are reused across dependents)*
174
+ *
175
+ * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#useKeyDownSequence
176
+ *
177
+ * @returns
178
+ * ```ts
179
+ * Accessor<string[][]>
180
+ * // [["CONTROL"], ["CONTROL", "Q"], ["CONTROL", "Q", "A"]]
181
+ * ```
182
+ *
183
+ * @example
184
+ * ```ts
185
+ * const sequence = useKeyDownSequence();
186
+ * createEffect(() => {
187
+ * console.log(sequence()) // => string[][]
188
+ * })
189
+ * ```
190
+ */
191
+ export const useKeyDownSequence = /*#__PURE__*/ createSingletonRoot(() => {
192
+ if (isServer) {
193
+ return () => [];
139
194
  }
140
- };
141
- const handleSequenceWithoutReset = (sequence2) => {
142
- const last = sequence2.at(-1);
143
- if (!last)
144
- return;
145
- const e = event();
146
- if (preventDefault && last.length < keys.length) {
147
- if (arrayEquals(last, keys.slice(0, keys.length - 1))) {
148
- e && e.preventDefault();
149
- }
150
- return;
195
+ const keys = useKeyDownList();
196
+ return createMemo(prev => {
197
+ if (keys().length === 0)
198
+ return [];
199
+ return [...prev, keys()];
200
+ }, []);
201
+ });
202
+ /**
203
+ * Provides a `boolean` signal indicating if provided {@link key} is currently being held down.
204
+ * Holding multiple keys at the same time will return `false` — holding only the specified one will return `true`.
205
+ *
206
+ * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#createKeyHold
207
+ *
208
+ * @param key The key to check for.
209
+ * @options The options for the key hold.
210
+ * - `preventDefault` — Controlls in the keydown event should have it's default action prevented. Enabled by default.
211
+ * @returns
212
+ * ```ts
213
+ * Accessor<boolean>
214
+ * ```
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * const isHeld = createKeyHold("ALT");
219
+ * createEffect(() => {
220
+ * console.log(isHeld()) // => boolean
221
+ * })
222
+ * ```
223
+ */
224
+ export function createKeyHold(key, options = {}) {
225
+ if (isServer) {
226
+ return () => false;
151
227
  }
152
- if (arrayEquals(last, keys)) {
153
- const prev = sequence2.at(-2);
154
- if (!prev || arrayEquals(prev, keys.slice(0, keys.length - 1))) {
155
- preventDefault && e && e.preventDefault();
156
- callback(e);
157
- }
228
+ key = key.toUpperCase();
229
+ const { preventDefault = true } = options, event = useKeyDownEvent(), heldKey = useCurrentlyHeldKey();
230
+ return createMemo(() => heldKey() === key && (preventDefault && event()?.preventDefault(), true));
231
+ }
232
+ /**
233
+ * Creates a keyboard shotcut observer. The provided {@link callback} will be called when the specified {@link keys} are pressed.
234
+ *
235
+ * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#createShortcut
236
+ *
237
+ * @param keys The sequence of keys to watch for.
238
+ * @param callback The callback to call when the keys are pressed.
239
+ * @options The options for the shortcut.
240
+ * - `preventDefault` — Controlls in the keydown event should have it's default action prevented. Enabled by default.
241
+ * - `requireReset` — If `true`, the shortcut will only be triggered once until all of the keys stop being pressed. Disabled by default.
242
+ *
243
+ * @example
244
+ * ```ts
245
+ * createShortcut(["CONTROL", "SHIFT", "C"], () => {
246
+ * console.log("Ctrl+Shift+C was pressed");
247
+ * });
248
+ * ```
249
+ */
250
+ export function createShortcut(keys, callback, options = {}) {
251
+ if (isServer || !keys.length) {
252
+ return;
158
253
  }
159
- };
160
- createEffect(
161
- on(sequence, options.requireReset ? handleSequenceWithReset : handleSequenceWithoutReset)
162
- );
254
+ keys = keys.map(key => key.toUpperCase());
255
+ const { preventDefault = true } = options, event = useKeyDownEvent(), sequence = useKeyDownSequence();
256
+ let reset = false;
257
+ // allow to check the sequence only once the user has released all keys
258
+ const handleSequenceWithReset = (sequence) => {
259
+ if (!sequence.length)
260
+ return (reset = false);
261
+ if (reset)
262
+ return;
263
+ const e = event();
264
+ if (sequence.length < keys.length) {
265
+ // optimistically preventDefault behavior if we yet don't have enough keys
266
+ if (equalsKeyHoldSequence(sequence, keys.slice(0, sequence.length))) {
267
+ preventDefault && e && e.preventDefault();
268
+ }
269
+ else {
270
+ reset = true;
271
+ }
272
+ }
273
+ else {
274
+ reset = true;
275
+ if (equalsKeyHoldSequence(sequence, keys)) {
276
+ preventDefault && e && e.preventDefault();
277
+ callback(e);
278
+ }
279
+ }
280
+ };
281
+ // allow checking the sequence even if the user is still holding down keys
282
+ const handleSequenceWithoutReset = (sequence) => {
283
+ const last = sequence.at(-1);
284
+ if (!last)
285
+ return;
286
+ const e = event();
287
+ // optimistically preventDefault behavior if we yet don't have enough keys
288
+ if (preventDefault && last.length < keys.length) {
289
+ if (arrayEquals(last, keys.slice(0, keys.length - 1))) {
290
+ e && e.preventDefault();
291
+ }
292
+ return;
293
+ }
294
+ if (arrayEquals(last, keys)) {
295
+ const prev = sequence.at(-2);
296
+ if (!prev || arrayEquals(prev, keys.slice(0, keys.length - 1))) {
297
+ preventDefault && e && e.preventDefault();
298
+ callback(e);
299
+ }
300
+ }
301
+ };
302
+ createEffect(on(sequence, options.requireReset ? handleSequenceWithReset : handleSequenceWithoutReset));
163
303
  }
164
-
165
- export { createKeyHold, createShortcut, useCurrentlyHeldKey, useKeyDownEvent, useKeyDownList, useKeyDownSequence };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solid-primitives/keyboard",
3
- "version": "1.2.8",
3
+ "version": "1.3.0",
4
4
  "description": "A library of reactive promitives helping handling user's keyboard input.",
5
5
  "author": "Damian Tarnwski <gthetarnav@gmail.com>",
6
6
  "contributors": [],
@@ -38,24 +38,20 @@
38
38
  "dist"
39
39
  ],
40
40
  "type": "module",
41
- "main": "./dist/index.cjs",
42
41
  "module": "./dist/index.js",
43
42
  "types": "./dist/index.d.ts",
44
43
  "browser": {},
45
44
  "exports": {
45
+ "@solid-primitives/source": "./src/index.ts",
46
46
  "import": {
47
47
  "types": "./dist/index.d.ts",
48
48
  "default": "./dist/index.js"
49
- },
50
- "require": {
51
- "types": "./dist/index.d.cts",
52
- "default": "./dist/index.cjs"
53
49
  }
54
50
  },
55
51
  "dependencies": {
56
- "@solid-primitives/event-listener": "^2.3.3",
57
- "@solid-primitives/utils": "^6.2.3",
58
- "@solid-primitives/rootless": "^1.4.5"
52
+ "@solid-primitives/event-listener": "^2.4.0",
53
+ "@solid-primitives/rootless": "^1.5.0",
54
+ "@solid-primitives/utils": "^6.3.0"
59
55
  },
60
56
  "peerDependencies": {
61
57
  "solid-js": "^1.6.12"
package/dist/index.cjs DELETED
@@ -1,168 +0,0 @@
1
- 'use strict';
2
-
3
- var eventListener = require('@solid-primitives/event-listener');
4
- var rootless = require('@solid-primitives/rootless');
5
- var utils = require('@solid-primitives/utils');
6
- var solidJs = require('solid-js');
7
- var web = require('solid-js/web');
8
-
9
- // src/index.ts
10
- function equalsKeyHoldSequence(sequence, model) {
11
- for (let i = sequence.length - 1; i >= 0; i--) {
12
- const _model = model.slice(0, i + 1);
13
- if (!utils.arrayEquals(sequence[i], _model))
14
- return false;
15
- }
16
- return true;
17
- }
18
- exports.useKeyDownEvent = /* @__PURE__ */ rootless.createSingletonRoot(
19
- () => {
20
- if (web.isServer) {
21
- return () => null;
22
- }
23
- const [event, setEvent] = solidJs.createSignal(null);
24
- eventListener.makeEventListener(window, "keydown", (e) => {
25
- setEvent(e);
26
- setTimeout(() => setEvent(null));
27
- });
28
- return event;
29
- }
30
- );
31
- exports.useKeyDownList = /* @__PURE__ */ rootless.createSingletonRoot(() => {
32
- if (web.isServer) {
33
- const keys = () => [];
34
- keys[0] = keys;
35
- keys[1] = { event: () => null };
36
- keys[Symbol.iterator] = function* () {
37
- yield keys[0];
38
- yield keys[1];
39
- };
40
- return keys;
41
- }
42
- const [pressedKeys, setPressedKeys] = solidJs.createSignal([]), reset = () => setPressedKeys([]), event = exports.useKeyDownEvent();
43
- eventListener.makeEventListener(window, "keydown", (e) => {
44
- if (e.repeat || typeof e.key !== "string")
45
- return;
46
- const key = e.key.toUpperCase(), currentKeys = pressedKeys();
47
- if (currentKeys.includes(key))
48
- return;
49
- const keys = [...currentKeys, key];
50
- if (currentKeys.length === 0 && key !== "ALT" && key !== "CONTROL" && key !== "META" && key !== "SHIFT") {
51
- if (e.shiftKey)
52
- keys.unshift("SHIFT");
53
- if (e.altKey)
54
- keys.unshift("ALT");
55
- if (e.ctrlKey)
56
- keys.unshift("CONTROL");
57
- if (e.metaKey)
58
- keys.unshift("META");
59
- }
60
- setPressedKeys(keys);
61
- });
62
- eventListener.makeEventListener(window, "keyup", (e) => {
63
- if (typeof e.key !== "string")
64
- return;
65
- const key = e.key.toUpperCase();
66
- setPressedKeys((prev) => prev.filter((_key) => _key !== key));
67
- });
68
- eventListener.makeEventListener(window, "blur", reset);
69
- eventListener.makeEventListener(window, "contextmenu", (e) => {
70
- e.defaultPrevented || reset();
71
- });
72
- pressedKeys[0] = pressedKeys;
73
- pressedKeys[1] = { event };
74
- pressedKeys[Symbol.iterator] = function* () {
75
- yield pressedKeys[0];
76
- yield pressedKeys[1];
77
- };
78
- return pressedKeys;
79
- });
80
- exports.useCurrentlyHeldKey = /* @__PURE__ */ rootless.createSingletonRoot(
81
- () => {
82
- if (web.isServer) {
83
- return () => null;
84
- }
85
- const keys = exports.useKeyDownList();
86
- let prevKeys = solidJs.untrack(keys);
87
- return solidJs.createMemo(() => {
88
- const _keys = keys();
89
- const prev = prevKeys;
90
- prevKeys = _keys;
91
- if (prev.length === 0 && _keys.length === 1)
92
- return _keys[0];
93
- return null;
94
- });
95
- }
96
- );
97
- exports.useKeyDownSequence = /* @__PURE__ */ rootless.createSingletonRoot(() => {
98
- if (web.isServer) {
99
- return () => [];
100
- }
101
- const keys = exports.useKeyDownList();
102
- return solidJs.createMemo((prev) => {
103
- if (keys().length === 0)
104
- return [];
105
- return [...prev, keys()];
106
- }, []);
107
- });
108
- function createKeyHold(key, options = {}) {
109
- if (web.isServer) {
110
- return () => false;
111
- }
112
- key = key.toUpperCase();
113
- const { preventDefault = true } = options, event = exports.useKeyDownEvent(), heldKey = exports.useCurrentlyHeldKey();
114
- return solidJs.createMemo(() => heldKey() === key && (preventDefault && event()?.preventDefault(), true));
115
- }
116
- function createShortcut(keys, callback, options = {}) {
117
- if (web.isServer || !keys.length) {
118
- return;
119
- }
120
- keys = keys.map((key) => key.toUpperCase());
121
- const { preventDefault = true } = options, event = exports.useKeyDownEvent(), sequence = exports.useKeyDownSequence();
122
- let reset = false;
123
- const handleSequenceWithReset = (sequence2) => {
124
- if (!sequence2.length)
125
- return reset = false;
126
- if (reset)
127
- return;
128
- const e = event();
129
- if (sequence2.length < keys.length) {
130
- if (equalsKeyHoldSequence(sequence2, keys.slice(0, sequence2.length))) {
131
- preventDefault && e && e.preventDefault();
132
- } else {
133
- reset = true;
134
- }
135
- } else {
136
- reset = true;
137
- if (equalsKeyHoldSequence(sequence2, keys)) {
138
- preventDefault && e && e.preventDefault();
139
- callback(e);
140
- }
141
- }
142
- };
143
- const handleSequenceWithoutReset = (sequence2) => {
144
- const last = sequence2.at(-1);
145
- if (!last)
146
- return;
147
- const e = event();
148
- if (preventDefault && last.length < keys.length) {
149
- if (utils.arrayEquals(last, keys.slice(0, keys.length - 1))) {
150
- e && e.preventDefault();
151
- }
152
- return;
153
- }
154
- if (utils.arrayEquals(last, keys)) {
155
- const prev = sequence2.at(-2);
156
- if (!prev || utils.arrayEquals(prev, keys.slice(0, keys.length - 1))) {
157
- preventDefault && e && e.preventDefault();
158
- callback(e);
159
- }
160
- }
161
- };
162
- solidJs.createEffect(
163
- solidJs.on(sequence, options.requireReset ? handleSequenceWithReset : handleSequenceWithoutReset)
164
- );
165
- }
166
-
167
- exports.createKeyHold = createKeyHold;
168
- exports.createShortcut = createShortcut;
package/dist/index.d.cts DELETED
@@ -1,147 +0,0 @@
1
- import { Accessor } from 'solid-js';
2
-
3
- type ModifierKey = "Alt" | "Control" | "Meta" | "Shift";
4
- type KbdKey = ModifierKey | (string & {});
5
- /**
6
- * Provides a signal with the last keydown event.
7
- *
8
- * The signal is `null` initially, and is reset to that after a timeout.
9
- *
10
- * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#useKeyDownEvent
11
- *
12
- * @returns
13
- * Returns a signal of the last keydown event
14
- * ```ts
15
- * Accessor<KeyboardEvent | null>
16
- * ```
17
- *
18
- * @example
19
- * ```ts
20
- * const event = useKeyDownEvent();
21
- *
22
- * createEffect(() => {
23
- * const e = event();
24
- * console.log(e) // => KeyboardEvent | null
25
- *
26
- * if (e) {
27
- * console.log(e.key) // => "Q" | "ALT" | ... or null
28
- * e.preventDefault(); // prevent default behavior or last keydown event
29
- * }
30
- * })
31
- * ```
32
- */
33
- declare const useKeyDownEvent: () => Accessor<KeyboardEvent | null>;
34
- /**
35
- * Provides a signal with the list of currently held keys, ordered from least recent to most recent.
36
- *
37
- * This is a [singleton root primitive](https://github.com/solidjs-community/solid-primitives/tree/main/packages/rootless#createSingletonRoot). *(signals and event-listeners are reused across dependents)*
38
- *
39
- * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#useKeyDownList
40
- *
41
- * @returns
42
- * Returns a signal of a list of keys
43
- * ```ts
44
- * Accessor<string[]>
45
- * ```
46
- *
47
- * @example
48
- * ```ts
49
- * const keys = useKeyDownList();
50
- * createEffect(() => {
51
- * console.log(keys()) // => ["ALT", "CONTROL", "Q", "A"]
52
- * })
53
- * ```
54
- */
55
- declare const useKeyDownList: () => Accessor<string[]>;
56
- /**
57
- * Provides a signal with the currently held single key. Pressing any other key at the same time will reset the signal to `null`.
58
- *
59
- * This is a [singleton root primitive](https://github.com/solidjs-community/solid-primitives/tree/main/packages/rootless#createSingletonRoot). *(signals and event-listeners are reused across dependents)*
60
- *
61
- * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#useCurrentlyHeldKey
62
- *
63
- * @returns
64
- * ```ts
65
- * Accessor<string | null>
66
- * ```
67
- *
68
- * @example
69
- * ```ts
70
- * const key = useCurrentlyHeldKey();
71
- * createEffect(() => {
72
- * console.log(key()) // => "Q" | "ALT" | ... or null
73
- * })
74
- * ```
75
- */
76
- declare const useCurrentlyHeldKey: () => Accessor<string | null>;
77
- /**
78
- * Provides a signal with a sequence of currently held keys, as they were pressed down and up.
79
- *
80
- * This is a [singleton root primitive](https://github.com/solidjs-community/solid-primitives/tree/main/packages/rootless#createSingletonRoot). *(signals and event-listeners are reused across dependents)*
81
- *
82
- * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#useKeyDownSequence
83
- *
84
- * @returns
85
- * ```ts
86
- * Accessor<string[][]>
87
- * // [["CONTROL"], ["CONTROL", "Q"], ["CONTROL", "Q", "A"]]
88
- * ```
89
- *
90
- * @example
91
- * ```ts
92
- * const sequence = useKeyDownSequence();
93
- * createEffect(() => {
94
- * console.log(sequence()) // => string[][]
95
- * })
96
- * ```
97
- */
98
- declare const useKeyDownSequence: () => Accessor<string[][]>;
99
- /**
100
- * Provides a `boolean` signal indicating if provided {@link key} is currently being held down.
101
- * Holding multiple keys at the same time will return `false` — holding only the specified one will return `true`.
102
- *
103
- * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#createKeyHold
104
- *
105
- * @param key The key to check for.
106
- * @options The options for the key hold.
107
- * - `preventDefault` — Controlls in the keydown event should have it's default action prevented. Enabled by default.
108
- * @returns
109
- * ```ts
110
- * Accessor<boolean>
111
- * ```
112
- *
113
- * @example
114
- * ```ts
115
- * const isHeld = createKeyHold("ALT");
116
- * createEffect(() => {
117
- * console.log(isHeld()) // => boolean
118
- * })
119
- * ```
120
- */
121
- declare function createKeyHold(key: KbdKey, options?: {
122
- preventDefault?: boolean;
123
- }): Accessor<boolean>;
124
- /**
125
- * Creates a keyboard shotcut observer. The provided {@link callback} will be called when the specified {@link keys} are pressed.
126
- *
127
- * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#createShortcut
128
- *
129
- * @param keys The sequence of keys to watch for.
130
- * @param callback The callback to call when the keys are pressed.
131
- * @options The options for the shortcut.
132
- * - `preventDefault` — Controlls in the keydown event should have it's default action prevented. Enabled by default.
133
- * - `requireReset` — If `true`, the shortcut will only be triggered once until all of the keys stop being pressed. Disabled by default.
134
- *
135
- * @example
136
- * ```ts
137
- * createShortcut(["CONTROL", "SHIFT", "C"], () => {
138
- * console.log("Ctrl+Shift+C was pressed");
139
- * });
140
- * ```
141
- */
142
- declare function createShortcut(keys: KbdKey[], callback: (event: KeyboardEvent | null) => void, options?: {
143
- preventDefault?: boolean;
144
- requireReset?: boolean;
145
- }): void;
146
-
147
- export { KbdKey, ModifierKey, createKeyHold, createShortcut, useCurrentlyHeldKey, useKeyDownEvent, useKeyDownList, useKeyDownSequence };