@tanstack/hotkeys 0.14.0 → 0.15.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/dist/_target-listeners.js +3 -2
- package/dist/hotkey-manager.js +38 -4
- package/package.json +1 -1
|
@@ -20,7 +20,8 @@ var TargetListeners = class {
|
|
|
20
20
|
const listener = (eventType) => (rawEvent) => {
|
|
21
21
|
const event = rawEvent;
|
|
22
22
|
let processed = this.#processed.get(event);
|
|
23
|
-
|
|
23
|
+
const first = !processed || processed.groups.has(ids);
|
|
24
|
+
if (!processed || first) {
|
|
24
25
|
processed = {
|
|
25
26
|
ids: /* @__PURE__ */ new Set(),
|
|
26
27
|
groups: /* @__PURE__ */ new Set()
|
|
@@ -33,7 +34,7 @@ var TargetListeners = class {
|
|
|
33
34
|
processed.ids.add(registrationId);
|
|
34
35
|
pending.add(registrationId);
|
|
35
36
|
}
|
|
36
|
-
this.dispatch(event, target, eventType, capture, pending);
|
|
37
|
+
this.dispatch(event, target, eventType, capture, pending, first);
|
|
37
38
|
};
|
|
38
39
|
group = {
|
|
39
40
|
ids,
|
package/dist/hotkey-manager.js
CHANGED
|
@@ -5,7 +5,7 @@ import { isHotkeySequence, isModifierKey, parseHotkey, rawHotkeyToParsedHotkey,
|
|
|
5
5
|
import { formatHotkey } from "./format.js";
|
|
6
6
|
import { matchKeyboardEvent } from "./_match.js";
|
|
7
7
|
import { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual } from "./match.js";
|
|
8
|
-
import { isEventForTarget, shouldIgnoreInputEvent } from "./_event-target.js";
|
|
8
|
+
import { getTargetDocument, isEventForTarget, shouldIgnoreInputEvent } from "./_event-target.js";
|
|
9
9
|
import { TargetListeners } from "./_target-listeners.js";
|
|
10
10
|
import { isRecordingEvent } from "./_recording-guard.js";
|
|
11
11
|
import { defaultHotkeyOptions, getDefaultIgnoreInputs, handleConflict, optionsEqual } from "./_registration.js";
|
|
@@ -125,6 +125,10 @@ var HotkeyManager = class HotkeyManager {
|
|
|
125
125
|
appHotkeys = new Store(null);
|
|
126
126
|
#platform;
|
|
127
127
|
#listeners = new TargetListeners((...args) => this.#processTargetEvent(...args));
|
|
128
|
+
/** Events that continue a sequence in progress, decided before any listener runs. */
|
|
129
|
+
#sequenceOwned = /* @__PURE__ */ new WeakMap();
|
|
130
|
+
/** Physical keys whose keydown a sequence owned, so their repeats and keyup are owned too. */
|
|
131
|
+
#sequenceOwnedKeys = /* @__PURE__ */ new Set();
|
|
128
132
|
constructor() {
|
|
129
133
|
this.#platform = detectPlatform();
|
|
130
134
|
}
|
|
@@ -285,9 +289,11 @@ var HotkeyManager = class HotkeyManager {
|
|
|
285
289
|
}
|
|
286
290
|
/**
|
|
287
291
|
* Processes keyboard events for a specific target and event type.
|
|
288
|
-
*
|
|
292
|
+
* A key that continues a sequence in progress belongs to that sequence, so
|
|
293
|
+
* chords skip it. Chords and first steps of sequences may both fire.
|
|
289
294
|
*/
|
|
290
|
-
#processTargetEvent(event, target, eventType, capture, ids) {
|
|
295
|
+
#processTargetEvent(event, target, eventType, capture, ids, first) {
|
|
296
|
+
if (first) this.#sequenceOwned.set(event, this.#isOwnedBySequence(event, eventType));
|
|
291
297
|
this.#processChords(event, target, eventType, capture, this.#registrationsIn(ids, capture, "chord"));
|
|
292
298
|
this.#processSequences(event, target, eventType, capture, this.#registrationsIn(ids, capture, "sequence"));
|
|
293
299
|
}
|
|
@@ -298,7 +304,7 @@ var HotkeyManager = class HotkeyManager {
|
|
|
298
304
|
registration.activeMatch = void 0;
|
|
299
305
|
}
|
|
300
306
|
}
|
|
301
|
-
if (isRecordingEvent(event)) return;
|
|
307
|
+
if (isRecordingEvent(event) || this.#sequenceOwned.get(event)) return;
|
|
302
308
|
const matches = /* @__PURE__ */ new Map();
|
|
303
309
|
let bestScore = 0;
|
|
304
310
|
for (const registration of registrations) {
|
|
@@ -329,6 +335,34 @@ var HotkeyManager = class HotkeyManager {
|
|
|
329
335
|
}
|
|
330
336
|
}
|
|
331
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* Whether the event continues or completes a sequence in progress whose
|
|
340
|
+
* target the event reaches. The repeats and keyup of a keydown that a
|
|
341
|
+
* sequence owns belong to the sequence too.
|
|
342
|
+
*/
|
|
343
|
+
#isOwnedBySequence(event, eventType) {
|
|
344
|
+
const key = event.code || normalizeKeyName(event.key);
|
|
345
|
+
if (eventType === "keyup") {
|
|
346
|
+
const ownedKeydown = this.#sequenceOwnedKeys.delete(key);
|
|
347
|
+
return this.#continuesSequence(event, eventType) || ownedKeydown;
|
|
348
|
+
}
|
|
349
|
+
if (event.repeat) return this.#sequenceOwnedKeys.has(key);
|
|
350
|
+
const owned = this.#continuesSequence(event, eventType);
|
|
351
|
+
if (owned) this.#sequenceOwnedKeys.add(key);
|
|
352
|
+
else this.#sequenceOwnedKeys.delete(key);
|
|
353
|
+
return owned;
|
|
354
|
+
}
|
|
355
|
+
#continuesSequence(event, eventType) {
|
|
356
|
+
if (isRecordingEvent(event) || normalizeKeyboardEvent(event).isComposing || isModifierKey(normalizeKeyName(event.key))) return false;
|
|
357
|
+
const path = event.composedPath();
|
|
358
|
+
const now = Date.now();
|
|
359
|
+
for (const registration of this.registrations.state.values()) {
|
|
360
|
+
if (registration.kind !== "sequence" || registration.currentIndex === 0 || !registration.options.enabled || registration.options.eventType !== eventType || now - registration.lastKeyTime > (registration.options.timeout ?? 1e3)) continue;
|
|
361
|
+
const target = registration.target;
|
|
362
|
+
if (path.includes(target.nodeType === 1 ? target : getTargetDocument(target)) && !(ignoresInputs(registration) && shouldIgnoreInputEvent(event, target, target)) && matchKeyboardEvent(event, registration.parsedSequence[registration.currentIndex], registration.options.platform).matched) return true;
|
|
363
|
+
}
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
332
366
|
#processSequences(event, target, eventType, capture, registrations) {
|
|
333
367
|
if (registrations.length === 0) return;
|
|
334
368
|
if (isRecordingEvent(event)) {
|