@solid-primitives/keyboard 1.3.5 → 2.0.0-next.1
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 +31 -9
- package/dist/index.d.ts +30 -7
- package/dist/index.js +162 -70
- package/package.json +12 -8
package/README.md
CHANGED
|
@@ -5,18 +5,20 @@
|
|
|
5
5
|
# @solid-primitives/keyboard
|
|
6
6
|
|
|
7
7
|
[](https://lerna.js.org/)
|
|
8
|
-
[](https://bundlephobia.com/package/@solid-primitives/keyboard)
|
|
9
9
|
[](https://www.npmjs.com/package/@solid-primitives/keyboard)
|
|
10
10
|
[](https://github.com/solidjs-community/solid-primitives#contribution-process)
|
|
11
|
+
[](https://vitest.dev)
|
|
11
12
|
|
|
12
|
-
A library of reactive
|
|
13
|
+
A library of reactive primitives for handling user keyboard input.
|
|
13
14
|
|
|
14
15
|
- [`useKeyDownEvent`](#usekeydownevent) — Provides a signal with the last keydown event.
|
|
15
|
-
- [`useKeyDownList`](#usekeydownlist) — Provides a signal with the list of currently held keys
|
|
16
|
+
- [`useKeyDownList`](#usekeydownlist) — Provides a signal with the list of currently held keys.
|
|
16
17
|
- [`useCurrentlyHeldKey`](#usecurrentlyheldkey) — Provides a signal with the currently held single key.
|
|
17
18
|
- [`useKeyDownSequence`](#usekeydownsequence) — Provides a signal with a sequence of currently held keys, as they were pressed down and up.
|
|
18
19
|
- [`createKeyHold`](#createkeyhold) — Provides a signal indicating if provided key is currently being held down.
|
|
19
|
-
- [`createShortcut`](#createshortcut) — Creates a keyboard
|
|
20
|
+
- [`createShortcut`](#createshortcut) — Creates a keyboard shortcut observer.
|
|
21
|
+
- [`createKeyDown`](#createkeydown) — Listens for a keydown event for a specific key on a document.
|
|
20
22
|
|
|
21
23
|
## Installation
|
|
22
24
|
|
|
@@ -62,7 +64,7 @@ This is a [singleton root](https://github.com/solidjs-community/solid-primitives
|
|
|
62
64
|
|
|
63
65
|
### How to use it
|
|
64
66
|
|
|
65
|
-
`useKeyDownList` takes no arguments
|
|
67
|
+
`useKeyDownList` takes no arguments and returns a signal with the list of currently held keys.
|
|
66
68
|
|
|
67
69
|
```tsx
|
|
68
70
|
import { useKeyDownList } from "@solid-primitives/keyboard";
|
|
@@ -143,7 +145,7 @@ const pressing = createKeyHold("Alt", { preventDefault: false });
|
|
|
143
145
|
|
|
144
146
|
## `createShortcut`
|
|
145
147
|
|
|
146
|
-
Creates a keyboard
|
|
148
|
+
Creates a keyboard shortcut observer. The provided callback will be called when the specified keys are pressed.
|
|
147
149
|
|
|
148
150
|
### How to use it
|
|
149
151
|
|
|
@@ -173,11 +175,31 @@ When `preventDefault` is `true`, `e.preventDefault()` will be called not only on
|
|
|
173
175
|
|
|
174
176
|
E.g. when listening for `Control + Shift + A`, all three keydown events will be prevented.
|
|
175
177
|
|
|
176
|
-
##
|
|
178
|
+
## `createKeyDown`
|
|
177
179
|
|
|
178
|
-
|
|
180
|
+
Listens for a `keydown` event for a specific key on a document. Useful for global keyboard handlers that need to respond to a single key without setting up a full shortcut.
|
|
179
181
|
|
|
180
|
-
|
|
182
|
+
### How to use it
|
|
183
|
+
|
|
184
|
+
`createKeyDown` takes three arguments:
|
|
185
|
+
|
|
186
|
+
- `key` — the key to listen for (matched against `event.key`)
|
|
187
|
+
- `callback` — handler called when the key is pressed, receives the `KeyboardEvent`
|
|
188
|
+
- `options` — additional configuration:
|
|
189
|
+
- `disabled` — a `boolean` or accessor; when `true` the listener is inactive. Reactive — the listener is added/removed as the value changes.
|
|
190
|
+
- `ownerDocument` — accessor returning the `Document` to attach the listener to. Defaults to `window.document`. Useful for iframes and portals.
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
import { createKeyDown } from "@solid-primitives/keyboard";
|
|
194
|
+
|
|
195
|
+
createKeyDown("Escape", e => close());
|
|
196
|
+
|
|
197
|
+
// with options
|
|
198
|
+
createKeyDown("Escape", e => close(), {
|
|
199
|
+
disabled: () => !isOpen(),
|
|
200
|
+
ownerDocument: () => iframeEl.contentDocument ?? document,
|
|
201
|
+
});
|
|
202
|
+
```
|
|
181
203
|
|
|
182
204
|
## Changelog
|
|
183
205
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type MaybeAccessor } from "@solid-primitives/utils";
|
|
1
2
|
import { type Accessor } from "solid-js";
|
|
2
3
|
export type ModifierKey = "Alt" | "Control" | "Meta" | "Shift";
|
|
3
4
|
export type KbdKey = ModifierKey | (string & {});
|
|
@@ -23,8 +24,8 @@ export type KbdKey = ModifierKey | (string & {});
|
|
|
23
24
|
* console.log(e) // => KeyboardEvent | null
|
|
24
25
|
*
|
|
25
26
|
* if (e) {
|
|
26
|
-
* console.log(e.key) // => "Q" | "ALT" | ...
|
|
27
|
-
* e.preventDefault();
|
|
27
|
+
* console.log(e.key) // => "Q" | "ALT" | ...
|
|
28
|
+
* e.preventDefault();
|
|
28
29
|
* }
|
|
29
30
|
* })
|
|
30
31
|
* ```
|
|
@@ -102,8 +103,8 @@ export declare const useKeyDownSequence: () => Accessor<string[][]>;
|
|
|
102
103
|
* @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#createKeyHold
|
|
103
104
|
*
|
|
104
105
|
* @param key The key to check for.
|
|
105
|
-
* @options The options for the key hold.
|
|
106
|
-
* - `preventDefault` —
|
|
106
|
+
* @param options The options for the key hold.
|
|
107
|
+
* - `preventDefault` — Controls if the keydown event should have its default action prevented. Enabled by default.
|
|
107
108
|
* @returns
|
|
108
109
|
* ```ts
|
|
109
110
|
* Accessor<boolean>
|
|
@@ -121,14 +122,14 @@ export declare function createKeyHold(key: KbdKey, options?: {
|
|
|
121
122
|
preventDefault?: boolean;
|
|
122
123
|
}): Accessor<boolean>;
|
|
123
124
|
/**
|
|
124
|
-
* Creates a keyboard
|
|
125
|
+
* Creates a keyboard shortcut observer. The provided {@link callback} will be called when the specified {@link keys} are pressed.
|
|
125
126
|
*
|
|
126
127
|
* @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#createShortcut
|
|
127
128
|
*
|
|
128
129
|
* @param keys The sequence of keys to watch for.
|
|
129
130
|
* @param callback The callback to call when the keys are pressed.
|
|
130
|
-
* @options The options for the shortcut.
|
|
131
|
-
* - `preventDefault` —
|
|
131
|
+
* @param options The options for the shortcut.
|
|
132
|
+
* - `preventDefault` — Controls if the keydown event should have its default action prevented. Enabled by default.
|
|
132
133
|
* - `requireReset` — If `true`, the shortcut will only be triggered once until all of the keys stop being pressed. Disabled by default.
|
|
133
134
|
*
|
|
134
135
|
* @example
|
|
@@ -142,3 +143,25 @@ export declare function createShortcut(keys: KbdKey[], callback: (event: Keyboar
|
|
|
142
143
|
preventDefault?: boolean;
|
|
143
144
|
requireReset?: boolean;
|
|
144
145
|
}): void;
|
|
146
|
+
export interface CreateKeyDownOptions {
|
|
147
|
+
/** Whether the listener should be inactive. */
|
|
148
|
+
disabled?: MaybeAccessor<boolean | undefined>;
|
|
149
|
+
/** The document to attach the listener to. Defaults to `window.document`. Useful for iframes. */
|
|
150
|
+
ownerDocument?: Accessor<Document | undefined>;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Listens for a keydown event for a specific key on a document.
|
|
154
|
+
* Supports a custom `ownerDocument` for use in iframes and portals.
|
|
155
|
+
*
|
|
156
|
+
* @param key The key to listen for (matched against `event.key`).
|
|
157
|
+
* @param callback Handler called when the key is pressed.
|
|
158
|
+
* @param options `disabled` and `ownerDocument` accessors.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* createKeyDown("Escape", e => close(), {
|
|
163
|
+
* ownerDocument: () => iframeEl.contentDocument ?? document,
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export declare function createKeyDown(key: KbdKey, callback: (event: KeyboardEvent) => void, options?: CreateKeyDownOptions): void;
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { makeEventListener } from "@solid-primitives/event-listener";
|
|
2
2
|
import { createSingletonRoot } from "@solid-primitives/rootless";
|
|
3
|
-
import { arrayEquals } from "@solid-primitives/utils";
|
|
4
|
-
import { createEffect, createMemo, createSignal,
|
|
5
|
-
import { isServer } from "
|
|
3
|
+
import { arrayEquals, INTERNAL_OPTIONS, access } from "@solid-primitives/utils";
|
|
4
|
+
import { createEffect, createMemo, createSignal, untrack } from "solid-js";
|
|
5
|
+
import { isServer } from "@solidjs/web";
|
|
6
6
|
function equalsKeyHoldSequence(sequence, model) {
|
|
7
7
|
for (let i = sequence.length - 1; i >= 0; i--) {
|
|
8
8
|
const _model = model.slice(0, i + 1);
|
|
@@ -33,8 +33,8 @@ function equalsKeyHoldSequence(sequence, model) {
|
|
|
33
33
|
* console.log(e) // => KeyboardEvent | null
|
|
34
34
|
*
|
|
35
35
|
* if (e) {
|
|
36
|
-
* console.log(e.key) // => "Q" | "ALT" | ...
|
|
37
|
-
* e.preventDefault();
|
|
36
|
+
* console.log(e.key) // => "Q" | "ALT" | ...
|
|
37
|
+
* e.preventDefault();
|
|
38
38
|
* }
|
|
39
39
|
* })
|
|
40
40
|
* ```
|
|
@@ -43,7 +43,7 @@ export const useKeyDownEvent = /*#__PURE__*/ createSingletonRoot(() => {
|
|
|
43
43
|
if (isServer) {
|
|
44
44
|
return () => null;
|
|
45
45
|
}
|
|
46
|
-
const [event, setEvent] = createSignal(null);
|
|
46
|
+
const [event, setEvent] = createSignal(null, INTERNAL_OPTIONS);
|
|
47
47
|
makeEventListener(window, "keydown", e => {
|
|
48
48
|
setEvent(e);
|
|
49
49
|
setTimeout(() => setEvent(null));
|
|
@@ -73,18 +73,10 @@ export const useKeyDownEvent = /*#__PURE__*/ createSingletonRoot(() => {
|
|
|
73
73
|
*/
|
|
74
74
|
export const useKeyDownList = /*#__PURE__*/ createSingletonRoot(() => {
|
|
75
75
|
if (isServer) {
|
|
76
|
-
|
|
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;
|
|
76
|
+
return () => [];
|
|
86
77
|
}
|
|
87
|
-
const [pressedKeys, setPressedKeys] = createSignal([]
|
|
78
|
+
const [pressedKeys, setPressedKeys] = createSignal([], INTERNAL_OPTIONS);
|
|
79
|
+
const reset = () => setPressedKeys([]);
|
|
88
80
|
makeEventListener(window, "keydown", e => {
|
|
89
81
|
// e.key may be undefined when used with <datalist> el
|
|
90
82
|
// gh issue: https://github.com/solidjs-community/solid-primitives/issues/246
|
|
@@ -116,20 +108,21 @@ export const useKeyDownList = /*#__PURE__*/ createSingletonRoot(() => {
|
|
|
116
108
|
if (typeof e.key !== "string")
|
|
117
109
|
return;
|
|
118
110
|
const key = e.key.toUpperCase();
|
|
119
|
-
|
|
111
|
+
// macOS never fires keyup for other keys held down together with Meta —
|
|
112
|
+
// only Meta's own keyup arrives — so its release must clear everything,
|
|
113
|
+
// or the other keys' stale state corrupts the next press.
|
|
114
|
+
// See https://github.com/solidjs-community/solid-primitives/issues/269
|
|
115
|
+
if (key === "META") {
|
|
116
|
+
reset();
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
setPressedKeys(prev => prev.filter(_key => _key !== key));
|
|
120
|
+
}
|
|
120
121
|
});
|
|
121
122
|
makeEventListener(window, "blur", reset);
|
|
122
123
|
makeEventListener(window, "contextmenu", e => {
|
|
123
124
|
e.defaultPrevented || reset();
|
|
124
125
|
});
|
|
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
126
|
return pressedKeys;
|
|
134
127
|
});
|
|
135
128
|
/**
|
|
@@ -193,11 +186,13 @@ export const useKeyDownSequence = /*#__PURE__*/ createSingletonRoot(() => {
|
|
|
193
186
|
return () => [];
|
|
194
187
|
}
|
|
195
188
|
const keys = useKeyDownList();
|
|
196
|
-
|
|
189
|
+
// createMemo's second arg is options (not initialValue). The prev
|
|
190
|
+
// parameter starts as undefined; handle it with a fallback.
|
|
191
|
+
return createMemo((prev) => {
|
|
197
192
|
if (keys().length === 0)
|
|
198
193
|
return [];
|
|
199
|
-
return [...prev, keys()];
|
|
200
|
-
}
|
|
194
|
+
return [...(prev ?? []), keys()];
|
|
195
|
+
});
|
|
201
196
|
});
|
|
202
197
|
/**
|
|
203
198
|
* Provides a `boolean` signal indicating if provided {@link key} is currently being held down.
|
|
@@ -206,8 +201,8 @@ export const useKeyDownSequence = /*#__PURE__*/ createSingletonRoot(() => {
|
|
|
206
201
|
* @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#createKeyHold
|
|
207
202
|
*
|
|
208
203
|
* @param key The key to check for.
|
|
209
|
-
* @options The options for the key hold.
|
|
210
|
-
* - `preventDefault` —
|
|
204
|
+
* @param options The options for the key hold.
|
|
205
|
+
* - `preventDefault` — Controls if the keydown event should have its default action prevented. Enabled by default.
|
|
211
206
|
* @returns
|
|
212
207
|
* ```ts
|
|
213
208
|
* Accessor<boolean>
|
|
@@ -226,18 +221,28 @@ export function createKeyHold(key, options = {}) {
|
|
|
226
221
|
return () => false;
|
|
227
222
|
}
|
|
228
223
|
key = key.toUpperCase();
|
|
229
|
-
const { preventDefault = true } = options
|
|
230
|
-
|
|
224
|
+
const { preventDefault = true } = options;
|
|
225
|
+
const heldKey = useCurrentlyHeldKey();
|
|
226
|
+
if (preventDefault) {
|
|
227
|
+
// Use a direct event listener for synchronous preventDefault — signal reads in event
|
|
228
|
+
// listeners return the pre-batch committed value, so we check e.key directly.
|
|
229
|
+
makeEventListener(window, "keydown", (e) => {
|
|
230
|
+
if (e.key.toUpperCase() === key) {
|
|
231
|
+
e.preventDefault();
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
return createMemo(() => heldKey() === key);
|
|
231
236
|
}
|
|
232
237
|
/**
|
|
233
|
-
* Creates a keyboard
|
|
238
|
+
* Creates a keyboard shortcut observer. The provided {@link callback} will be called when the specified {@link keys} are pressed.
|
|
234
239
|
*
|
|
235
240
|
* @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyboard#createShortcut
|
|
236
241
|
*
|
|
237
242
|
* @param keys The sequence of keys to watch for.
|
|
238
243
|
* @param callback The callback to call when the keys are pressed.
|
|
239
|
-
* @options The options for the shortcut.
|
|
240
|
-
* - `preventDefault` —
|
|
244
|
+
* @param options The options for the shortcut.
|
|
245
|
+
* - `preventDefault` — Controls if the keydown event should have its default action prevented. Enabled by default.
|
|
241
246
|
* - `requireReset` — If `true`, the shortcut will only be triggered once until all of the keys stop being pressed. Disabled by default.
|
|
242
247
|
*
|
|
243
248
|
* @example
|
|
@@ -252,52 +257,139 @@ export function createShortcut(keys, callback, options = {}) {
|
|
|
252
257
|
return;
|
|
253
258
|
}
|
|
254
259
|
keys = keys.map(key => key.toUpperCase());
|
|
255
|
-
const { preventDefault = true
|
|
260
|
+
const { preventDefault = true, requireReset = false } = options;
|
|
261
|
+
// Track pressed keys and sequence locally with plain JS state rather than
|
|
262
|
+
// reactive signals. A signal reads from event listeners return
|
|
263
|
+
// the pre-batch committed value, so synchronous shortcut checking requires
|
|
264
|
+
// imperative state that's updated in the same event listener tick.
|
|
265
|
+
let pressedKeys = [];
|
|
266
|
+
let sequence = [];
|
|
256
267
|
let reset = false;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
268
|
+
const resetAll = () => {
|
|
269
|
+
pressedKeys = [];
|
|
270
|
+
sequence = [];
|
|
271
|
+
reset = false;
|
|
272
|
+
};
|
|
273
|
+
makeEventListener(window, "keydown", (e) => {
|
|
274
|
+
if (e.repeat || typeof e.key !== "string")
|
|
262
275
|
return;
|
|
263
|
-
const
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
276
|
+
const key = e.key.toUpperCase();
|
|
277
|
+
if (!pressedKeys.includes(key)) {
|
|
278
|
+
const newKeys = [...pressedKeys];
|
|
279
|
+
// Detect modifiers pressed before listener attached
|
|
280
|
+
if (pressedKeys.length === 0 &&
|
|
281
|
+
key !== "ALT" &&
|
|
282
|
+
key !== "CONTROL" &&
|
|
283
|
+
key !== "META" &&
|
|
284
|
+
key !== "SHIFT") {
|
|
285
|
+
if (e.shiftKey && !newKeys.includes("SHIFT"))
|
|
286
|
+
newKeys.unshift("SHIFT");
|
|
287
|
+
if (e.altKey && !newKeys.includes("ALT"))
|
|
288
|
+
newKeys.unshift("ALT");
|
|
289
|
+
if (e.ctrlKey && !newKeys.includes("CONTROL"))
|
|
290
|
+
newKeys.unshift("CONTROL");
|
|
291
|
+
if (e.metaKey && !newKeys.includes("META"))
|
|
292
|
+
newKeys.unshift("META");
|
|
293
|
+
}
|
|
294
|
+
newKeys.push(key);
|
|
295
|
+
pressedKeys = newKeys;
|
|
296
|
+
sequence = [...sequence, [...pressedKeys]];
|
|
297
|
+
}
|
|
298
|
+
if (requireReset) {
|
|
299
|
+
if (reset)
|
|
300
|
+
return;
|
|
301
|
+
if (sequence.length < keys.length) {
|
|
302
|
+
if (equalsKeyHoldSequence(sequence, keys.slice(0, sequence.length))) {
|
|
303
|
+
preventDefault && e.preventDefault();
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
reset = true;
|
|
307
|
+
}
|
|
268
308
|
}
|
|
269
309
|
else {
|
|
270
310
|
reset = true;
|
|
311
|
+
if (equalsKeyHoldSequence(sequence, keys)) {
|
|
312
|
+
preventDefault && e.preventDefault();
|
|
313
|
+
callback(e);
|
|
314
|
+
}
|
|
271
315
|
}
|
|
272
316
|
}
|
|
273
317
|
else {
|
|
274
|
-
|
|
275
|
-
if (
|
|
276
|
-
|
|
277
|
-
|
|
318
|
+
const last = sequence.at(-1);
|
|
319
|
+
if (!last)
|
|
320
|
+
return;
|
|
321
|
+
if (preventDefault && last.length < keys.length) {
|
|
322
|
+
if (arrayEquals(last, keys.slice(0, keys.length - 1))) {
|
|
323
|
+
e.preventDefault();
|
|
324
|
+
}
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (arrayEquals(last, keys)) {
|
|
328
|
+
const prev = sequence.at(-2);
|
|
329
|
+
if (!prev || arrayEquals(prev, keys.slice(0, keys.length - 1))) {
|
|
330
|
+
preventDefault && e.preventDefault();
|
|
331
|
+
callback(e);
|
|
332
|
+
}
|
|
278
333
|
}
|
|
279
334
|
}
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const last = sequence.at(-1);
|
|
284
|
-
if (!last)
|
|
335
|
+
});
|
|
336
|
+
makeEventListener(window, "keyup", (e) => {
|
|
337
|
+
if (typeof e.key !== "string")
|
|
285
338
|
return;
|
|
286
|
-
const
|
|
287
|
-
//
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
339
|
+
const key = e.key.toUpperCase();
|
|
340
|
+
// macOS never fires keyup for other keys held down together with Meta —
|
|
341
|
+
// only Meta's own keyup arrives. Treat it as a signal that every other
|
|
342
|
+
// tracked key must have been released too, or their stale state corrupts
|
|
343
|
+
// the next press (see https://github.com/solidjs-community/solid-primitives/issues/269).
|
|
344
|
+
if (key === "META") {
|
|
345
|
+
resetAll();
|
|
292
346
|
return;
|
|
293
347
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
callback(e);
|
|
299
|
-
}
|
|
348
|
+
pressedKeys = pressedKeys.filter(k => k !== key);
|
|
349
|
+
if (pressedKeys.length === 0) {
|
|
350
|
+
sequence = [];
|
|
351
|
+
reset = false;
|
|
300
352
|
}
|
|
301
|
-
|
|
302
|
-
|
|
353
|
+
else {
|
|
354
|
+
// Reset sequence to remaining held keys so repeated presses of the last
|
|
355
|
+
// key can re-trigger the shortcut while modifier keys stay held.
|
|
356
|
+
sequence = [[...pressedKeys]];
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
makeEventListener(window, "blur", resetAll);
|
|
360
|
+
makeEventListener(window, "contextmenu", (e) => {
|
|
361
|
+
e.defaultPrevented || resetAll();
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Listens for a keydown event for a specific key on a document.
|
|
366
|
+
* Supports a custom `ownerDocument` for use in iframes and portals.
|
|
367
|
+
*
|
|
368
|
+
* @param key The key to listen for (matched against `event.key`).
|
|
369
|
+
* @param callback Handler called when the key is pressed.
|
|
370
|
+
* @param options `disabled` and `ownerDocument` accessors.
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```ts
|
|
374
|
+
* createKeyDown("Escape", e => close(), {
|
|
375
|
+
* ownerDocument: () => iframeEl.contentDocument ?? document,
|
|
376
|
+
* });
|
|
377
|
+
* ```
|
|
378
|
+
*/
|
|
379
|
+
export function createKeyDown(key, callback, options) {
|
|
380
|
+
if (isServer)
|
|
381
|
+
return;
|
|
382
|
+
createEffect(() => ({
|
|
383
|
+
disabled: !!access(options?.disabled),
|
|
384
|
+
document: options?.ownerDocument?.() ?? window.document,
|
|
385
|
+
}), ({ disabled, document }) => {
|
|
386
|
+
if (disabled)
|
|
387
|
+
return;
|
|
388
|
+
const handler = (e) => {
|
|
389
|
+
if (e.key === key)
|
|
390
|
+
callback(e);
|
|
391
|
+
};
|
|
392
|
+
document.addEventListener("keydown", handler);
|
|
393
|
+
return () => document.removeEventListener("keydown", handler);
|
|
394
|
+
});
|
|
303
395
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solid-primitives/keyboard",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-next.1",
|
|
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": [],
|
|
@@ -15,15 +15,17 @@
|
|
|
15
15
|
},
|
|
16
16
|
"primitive": {
|
|
17
17
|
"name": "keyboard",
|
|
18
|
-
"stage":
|
|
18
|
+
"stage": 3,
|
|
19
19
|
"list": [
|
|
20
|
+
"useKeyDownEvent",
|
|
20
21
|
"useKeyDownList",
|
|
21
22
|
"useCurrentlyHeldKey",
|
|
22
23
|
"useKeyDownSequence",
|
|
23
24
|
"createKeyHold",
|
|
24
25
|
"createShortcut"
|
|
25
26
|
],
|
|
26
|
-
"category": "Inputs"
|
|
27
|
+
"category": "Inputs",
|
|
28
|
+
"gzip": 1348
|
|
27
29
|
},
|
|
28
30
|
"keywords": [
|
|
29
31
|
"solid",
|
|
@@ -49,15 +51,17 @@
|
|
|
49
51
|
}
|
|
50
52
|
},
|
|
51
53
|
"dependencies": {
|
|
52
|
-
"@solid-primitives/event-listener": "^
|
|
53
|
-
"@solid-primitives/rootless": "^
|
|
54
|
-
"@solid-primitives/utils": "^
|
|
54
|
+
"@solid-primitives/event-listener": "^3.0.0-next.0",
|
|
55
|
+
"@solid-primitives/rootless": "^2.0.0-next.0",
|
|
56
|
+
"@solid-primitives/utils": "^7.0.0-next.0"
|
|
55
57
|
},
|
|
56
58
|
"peerDependencies": {
|
|
57
|
-
"
|
|
59
|
+
"@solidjs/web": "^2.0.0-beta.15",
|
|
60
|
+
"solid-js": "^2.0.0-beta.15"
|
|
58
61
|
},
|
|
59
62
|
"devDependencies": {
|
|
60
|
-
"
|
|
63
|
+
"@solidjs/web": "2.0.0-beta.15",
|
|
64
|
+
"solid-js": "2.0.0-beta.15"
|
|
61
65
|
},
|
|
62
66
|
"typesVersions": {},
|
|
63
67
|
"scripts": {
|