@tanstack/hotkeys 0.23.0 → 0.25.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/_app-hotkeys-factory.d.ts +1 -3
- package/dist/_app-hotkeys-factory.js +2 -3
- package/dist/_event-target.js +40 -7
- package/dist/_keyboard-event.js +8 -5
- package/dist/_manager-ref.js +1 -2
- package/dist/_match.js +5 -3
- package/dist/_named-keys.d.ts +1 -3
- package/dist/_named-keys.js +1 -2
- package/dist/_recorder-chord.js +7 -13
- package/dist/_recording-guard.js +1 -2
- package/dist/_registration.d.ts +1 -3
- package/dist/_registration.js +11 -6
- package/dist/_server.js +3 -4
- package/dist/_store.d.ts +1 -3
- package/dist/_store.js +1 -2
- package/dist/_target-listeners.js +11 -3
- package/dist/adapter.d.ts +10 -8
- package/dist/adapter.js +9 -5
- package/dist/app-hotkeys.d.ts +4 -5
- package/dist/app-hotkeys.js +10 -21
- package/dist/conflicts.d.ts +2 -4
- package/dist/conflicts.js +5 -6
- package/dist/constants.d.ts +2 -4
- package/dist/constants.js +1 -2
- package/dist/display-labels.d.ts +1 -3
- package/dist/display-labels.js +1 -2
- package/dist/format.d.ts +2 -4
- package/dist/format.js +4 -5
- package/dist/hint.d.ts +1 -3
- package/dist/hint.js +1 -2
- package/dist/hotkey-manager.d.ts +23 -4
- package/dist/hotkey-manager.js +138 -30
- package/dist/hotkey-recorder.d.ts +19 -7
- package/dist/hotkey-recorder.js +8 -11
- package/dist/hotkey.types.d.ts +1 -3
- package/dist/index.d.ts +8 -8
- package/dist/index.js +3 -3
- package/dist/key-state-tracker.d.ts +1 -3
- package/dist/key-state-tracker.js +2 -3
- package/dist/key.types.d.ts +5 -6
- package/dist/match.d.ts +4 -5
- package/dist/match.js +7 -7
- package/dist/parse.d.ts +2 -3
- package/dist/parse.js +10 -19
- package/dist/platform.d.ts +1 -3
- package/dist/platform.js +1 -2
- package/dist/validate.d.ts +33 -13
- package/dist/validate.js +51 -34
- package/dist/vendor/@tanstack/store/dist/store.d.ts +0 -2
- package/dist/vendor/@tanstack/store/dist/types.d.ts +0 -2
- package/package.json +4 -4
- package/skills/app-hotkeys/SKILL.md +1 -1
- package/skills/hotkeys-core/SKILL.md +3 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { CanonicalModifier, EditingKey, FunctionKey, IndividualKey, Key, LetterKey, LogicalKey, Modifier, NamedKey, NavigationKey, NonPunctuationKey, NormalizedKeyboardEvent, NumberKey, PhysicalKey, PhysicalKeyCode, PunctuationKey } from "./key.types.js";
|
|
2
|
-
import { ConflictBehavior, FourModifierHotkeyChord, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyCallbackContextFor, HotkeyChord, HotkeyChordCallbackContext, HotkeyMeta, HotkeySequence, HotkeySequenceCallbackContext, ParsedHotkeyChord, ParsedModifiers, RawHotkeyChord, RawModifiers, RegisterableHotkey, RegisterableHotkeyChord, RegisterableHotkeySequence, SingleModifierHotkeyChord, ThreeModifierHotkeyChord, TwoModifierHotkeyChord } from "./hotkey.types.js";
|
|
3
|
-
import { ActivateHotkeyScopeOptions, HotkeyChordOptions, HotkeyChordRegistration, HotkeyChordRegistrationView, HotkeyManager, HotkeyOptions, HotkeyOptionsFor, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationStatus, HotkeyRegistrationView, HotkeyScopesState, HotkeySequenceOptions, HotkeySequenceRegistration, HotkeySequenceRegistrationView, Target, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
|
|
4
|
-
import { AppHotkey, AppHotkeyChordOptions, AppHotkeyDefaultKind, AppHotkeyId, AppHotkeyInput, AppHotkeyListItem, AppHotkeyOptions, AppHotkeySequenceOptions, AppHotkeyStatus, AppHotkeys, AppHotkeysState, AppHotkeysStore, AppHotkeysStoreOptions, CustomHotkeys, DefinedAppHotkeys, Register, RegisteredAppHotkeys, defineAppHotkeys, getAppHotkeyRegistrationOptions, isAppHotkey, isCustomHotkey, provideAppHotkeys, publishAppHotkeysStore, resolveAppHotkey } from "./app-hotkeys.js";
|
|
5
|
-
import { HotkeyPlatform, detectPlatform, resolveModifier } from "./platform.js";
|
|
6
1
|
import { ALL_KEYS, EDITING_KEYS, FUNCTION_KEYS, LETTER_KEYS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, isSingleLetterKey, normalizeKeyName } from "./constants.js";
|
|
7
2
|
import { KEY_DISPLAY_SYMBOLS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS } from "./display-labels.js";
|
|
3
|
+
import { HotkeyPlatform, detectPlatform, resolveModifier } from "./platform.js";
|
|
4
|
+
import { CanonicalModifier, EditingKey, FunctionKey, IndividualKey, Key, LetterKey, LogicalKey, Modifier, NamedKey, NavigationKey, NonPunctuationKey, NormalizedKeyboardEvent, NumberKey, PhysicalKey, PhysicalKeyCode, PunctuationKey } from "./key.types.js";
|
|
5
|
+
import { ConflictBehavior, FourModifierHotkeyChord, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyCallbackContextFor, HotkeyChord, HotkeyChordCallbackContext, HotkeyMeta, HotkeySequence, HotkeySequenceCallbackContext, ParsedHotkeyChord, ParsedModifiers, RawHotkeyChord, RawModifiers, RegisterableHotkey, RegisterableHotkeyChord, RegisterableHotkeySequence, SingleModifierHotkeyChord, ThreeModifierHotkeyChord, TwoModifierHotkeyChord } from "./hotkey.types.js";
|
|
8
6
|
import { DisplayHotkey, DisplayHotkeyChord, FormatDisplayOptions, formatForDisplay, formatHotkey } from "./format.js";
|
|
9
7
|
import { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey, parseHotkey, parseKeyboardEvent, simplifyHotkey } from "./parse.js";
|
|
10
|
-
import { ValidatableHotkey, ValidationResult, assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
|
|
8
|
+
import { HotkeyIssue, HotkeyIssueReason, ValidatableHotkey, ValidationResult, assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
|
|
11
9
|
import { CreateHotkeyChordHandlerOptions, DEFAULT_SEQUENCE_TIMEOUT, KeyboardEventMatch, MultiHotkeyChordHandler, areHotkeysEqual, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, matchesKeyboardEvent } from "./match.js";
|
|
12
10
|
import { HeldModifierOptions, matchesHeldModifiers } from "./hint.js";
|
|
13
11
|
import { HotkeyConflict, HotkeyConflictOptions, findHotkeyConflicts } from "./conflicts.js";
|
|
12
|
+
import { ActivateHotkeyScopeOptions, HotkeyChordOptions, HotkeyChordRegistration, HotkeyChordRegistrationView, HotkeyManager, HotkeyOptions, HotkeyOptionsFor, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationStatus, HotkeyRegistrationView, HotkeyScopesState, HotkeySequenceOptions, HotkeySequenceRegistration, HotkeySequenceRegistrationView, Target, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
|
|
13
|
+
import { AppHotkey, AppHotkeyChordOptions, AppHotkeyDefaultKind, AppHotkeyId, AppHotkeyInput, AppHotkeyListItem, AppHotkeyOptions, AppHotkeySequenceOptions, AppHotkeyStatus, AppHotkeys, AppHotkeysState, AppHotkeysStore, AppHotkeysStoreOptions, CustomHotkeys, DefinedAppHotkeys, Register, RegisteredAppHotkeys, defineAppHotkeys, getAppHotkeyRegistrationOptions, isAppHotkey, isCustomHotkey, provideAppHotkeys, publishAppHotkeysStore, resolveAppHotkey } from "./app-hotkeys.js";
|
|
14
14
|
import { KeyStateTracker, KeyStateTrackerState, getKeyStateTracker } from "./key-state-tracker.js";
|
|
15
|
-
import { HotkeyChordRecorderOptions, HotkeyChordRecorderValidationContext, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeySequenceRecorderOptions, HotkeySequenceRecorderValidationContext, RecorderKeyMode, RecorderOptions, RecorderRejection } from "./hotkey-recorder.js";
|
|
15
|
+
import { HotkeyChordRecorderOptions, HotkeyChordRecorderValidationContext, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeySequenceRecorderOptions, HotkeySequenceRecorderValidationContext, RecorderKeyMode, RecorderOptions, RecorderRejection, RecorderRejectionReason } from "./hotkey-recorder.js";
|
|
16
16
|
import { createAppHotkeysStore } from "./_app-hotkeys-factory.js";
|
|
17
|
-
export { ALL_KEYS, ActivateHotkeyScopeOptions, AppHotkey, AppHotkeyChordOptions, AppHotkeyDefaultKind, AppHotkeyId, AppHotkeyInput, AppHotkeyListItem, AppHotkeyOptions, AppHotkeySequenceOptions, AppHotkeyStatus, AppHotkeys, AppHotkeysState, AppHotkeysStore, AppHotkeysStoreOptions, CanonicalModifier, ConflictBehavior, CreateHotkeyChordHandlerOptions, CustomHotkeys, DEFAULT_SEQUENCE_TIMEOUT, DefinedAppHotkeys, DisplayHotkey, DisplayHotkeyChord, EDITING_KEYS, EditingKey, FUNCTION_KEYS, FormatDisplayOptions, FourModifierHotkeyChord, FunctionKey, HeldModifierOptions, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyCallbackContextFor, HotkeyChord, HotkeyChordCallbackContext, HotkeyChordOptions, HotkeyChordRecorderOptions, HotkeyChordRecorderValidationContext, HotkeyChordRegistration, HotkeyChordRegistrationView, HotkeyConflict, HotkeyConflictOptions, HotkeyManager, HotkeyMeta, HotkeyOptions, HotkeyOptionsFor, HotkeyPlatform, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationStatus, HotkeyRegistrationView, HotkeyScopesState, HotkeySequence, HotkeySequenceCallbackContext, HotkeySequenceOptions, HotkeySequenceRecorderOptions, HotkeySequenceRecorderValidationContext, HotkeySequenceRegistration, HotkeySequenceRegistrationView, IndividualKey, KEY_DISPLAY_SYMBOLS, Key, KeyStateTracker, KeyStateTrackerState, KeyboardEventMatch, LETTER_KEYS, LINUX_MODIFIER_LABELS, LetterKey, LogicalKey, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, Modifier, MultiHotkeyChordHandler, NAVIGATION_KEYS, NUMBER_KEYS, NamedKey, NavigationKey, NonPunctuationKey, NormalizedKeyboardEvent, NumberKey, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, ParsedHotkeyChord, ParsedModifiers, PhysicalKey, PhysicalKeyCode, PunctuationKey, RawHotkeyChord, RawModifiers, RecorderKeyMode, RecorderOptions, RecorderRejection, Register, RegisterableHotkey, RegisterableHotkeyChord, RegisterableHotkeySequence, RegisteredAppHotkeys, SingleModifierHotkeyChord, Target, ThreeModifierHotkeyChord, TwoModifierHotkeyChord, ValidatableHotkey, ValidationResult, WINDOWS_MODIFIER_LABELS, areHotkeysEqual, assertValidHotkey, checkHotkey, createAppHotkeysStore, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, defineAppHotkeys, detectPlatform, findHotkeyConflicts, formatForDisplay, formatHotkey, getAppHotkeyRegistrationOptions, getHotkeyManager, getKeyStateTracker, hasNonModifierKey, isAppHotkey, isCustomHotkey, isHotkeySequence, isModifierKey, isSingleLetterKey, matchesHeldModifiers, matchesKeyboardEvent, normalizeHotkey, normalizeKeyName, parseHotkey, parseKeyboardEvent, provideAppHotkeys, publishAppHotkeysStore, resolveAppHotkey, resolveModifier, simplifyHotkey, toHotkeyRegistrationView, validateHotkey };
|
|
17
|
+
export { ALL_KEYS, ActivateHotkeyScopeOptions, AppHotkey, AppHotkeyChordOptions, AppHotkeyDefaultKind, AppHotkeyId, AppHotkeyInput, AppHotkeyListItem, AppHotkeyOptions, AppHotkeySequenceOptions, AppHotkeyStatus, AppHotkeys, AppHotkeysState, AppHotkeysStore, AppHotkeysStoreOptions, CanonicalModifier, ConflictBehavior, CreateHotkeyChordHandlerOptions, CustomHotkeys, DEFAULT_SEQUENCE_TIMEOUT, DefinedAppHotkeys, DisplayHotkey, DisplayHotkeyChord, EDITING_KEYS, EditingKey, FUNCTION_KEYS, FormatDisplayOptions, FourModifierHotkeyChord, FunctionKey, HeldModifierOptions, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyCallbackContextFor, HotkeyChord, HotkeyChordCallbackContext, HotkeyChordOptions, HotkeyChordRecorderOptions, HotkeyChordRecorderValidationContext, HotkeyChordRegistration, HotkeyChordRegistrationView, HotkeyConflict, HotkeyConflictOptions, HotkeyIssue, HotkeyIssueReason, HotkeyManager, HotkeyMeta, HotkeyOptions, HotkeyOptionsFor, HotkeyPlatform, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationStatus, HotkeyRegistrationView, HotkeyScopesState, HotkeySequence, HotkeySequenceCallbackContext, HotkeySequenceOptions, HotkeySequenceRecorderOptions, HotkeySequenceRecorderValidationContext, HotkeySequenceRegistration, HotkeySequenceRegistrationView, IndividualKey, KEY_DISPLAY_SYMBOLS, Key, KeyStateTracker, KeyStateTrackerState, KeyboardEventMatch, LETTER_KEYS, LINUX_MODIFIER_LABELS, LetterKey, LogicalKey, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, Modifier, MultiHotkeyChordHandler, NAVIGATION_KEYS, NUMBER_KEYS, NamedKey, NavigationKey, NonPunctuationKey, NormalizedKeyboardEvent, NumberKey, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, ParsedHotkeyChord, ParsedModifiers, PhysicalKey, PhysicalKeyCode, PunctuationKey, RawHotkeyChord, RawModifiers, RecorderKeyMode, RecorderOptions, RecorderRejection, RecorderRejectionReason, Register, RegisterableHotkey, RegisterableHotkeyChord, RegisterableHotkeySequence, RegisteredAppHotkeys, SingleModifierHotkeyChord, Target, ThreeModifierHotkeyChord, TwoModifierHotkeyChord, ValidatableHotkey, ValidationResult, WINDOWS_MODIFIER_LABELS, areHotkeysEqual, assertValidHotkey, checkHotkey, createAppHotkeysStore, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, defineAppHotkeys, detectPlatform, findHotkeyConflicts, formatForDisplay, formatHotkey, getAppHotkeyRegistrationOptions, getHotkeyManager, getKeyStateTracker, hasNonModifierKey, isAppHotkey, isCustomHotkey, isHotkeySequence, isModifierKey, isSingleLetterKey, matchesHeldModifiers, matchesKeyboardEvent, normalizeHotkey, normalizeKeyName, parseHotkey, parseKeyboardEvent, provideAppHotkeys, publishAppHotkeysStore, resolveAppHotkey, resolveModifier, simplifyHotkey, toHotkeyRegistrationView, validateHotkey };
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { ALL_KEYS, EDITING_KEYS, FUNCTION_KEYS, LETTER_KEYS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, isSingleLetterKey, normalizeKeyName } from "./constants.js";
|
|
2
2
|
import { KEY_DISPLAY_SYMBOLS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS } from "./display-labels.js";
|
|
3
3
|
import { detectPlatform, resolveModifier } from "./platform.js";
|
|
4
|
-
import { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey, parseHotkey, parseKeyboardEvent, simplifyHotkey } from "./parse.js";
|
|
5
4
|
import { formatForDisplay, formatHotkey } from "./format.js";
|
|
5
|
+
import { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey, parseHotkey, parseKeyboardEvent, simplifyHotkey } from "./parse.js";
|
|
6
6
|
import { assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
|
|
7
7
|
import { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, matchesKeyboardEvent } from "./match.js";
|
|
8
8
|
import { matchesHeldModifiers } from "./hint.js";
|
|
9
|
-
import { HotkeyManager, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
|
|
10
9
|
import { findHotkeyConflicts } from "./conflicts.js";
|
|
11
|
-
import {
|
|
10
|
+
import { HotkeyManager, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
|
|
12
11
|
import { AppHotkeysStore, defineAppHotkeys, getAppHotkeyRegistrationOptions, isAppHotkey, isCustomHotkey, provideAppHotkeys, publishAppHotkeysStore, resolveAppHotkey } from "./app-hotkeys.js";
|
|
13
12
|
import { KeyStateTracker, getKeyStateTracker } from "./key-state-tracker.js";
|
|
14
13
|
import { HotkeyRecorder } from "./hotkey-recorder.js";
|
|
14
|
+
import { createAppHotkeysStore } from "./_app-hotkeys-factory.js";
|
|
15
15
|
|
|
16
16
|
export { ALL_KEYS, AppHotkeysStore, DEFAULT_SEQUENCE_TIMEOUT, EDITING_KEYS, FUNCTION_KEYS, HotkeyManager, HotkeyRecorder, KEY_DISPLAY_SYMBOLS, KeyStateTracker, LETTER_KEYS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS, areHotkeysEqual, assertValidHotkey, checkHotkey, createAppHotkeysStore, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, defineAppHotkeys, detectPlatform, findHotkeyConflicts, formatForDisplay, formatHotkey, getAppHotkeyRegistrationOptions, getHotkeyManager, getKeyStateTracker, hasNonModifierKey, isAppHotkey, isCustomHotkey, isHotkeySequence, isModifierKey, isSingleLetterKey, matchesHeldModifiers, matchesKeyboardEvent, normalizeHotkey, normalizeKeyName, parseHotkey, parseKeyboardEvent, provideAppHotkeys, publishAppHotkeysStore, resolveAppHotkey, resolveModifier, simplifyHotkey, toHotkeyRegistrationView, validateHotkey };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Store } from "./_store.js";
|
|
2
|
-
//#region src/key-state-tracker.d.ts
|
|
3
2
|
/**
|
|
4
3
|
* State interface for the KeyStateTracker.
|
|
5
4
|
*/
|
|
@@ -100,5 +99,4 @@ export declare class KeyStateTracker {
|
|
|
100
99
|
* Gets the singleton KeyStateTracker instance.
|
|
101
100
|
* Convenience function for accessing the tracker.
|
|
102
101
|
*/
|
|
103
|
-
export declare function getKeyStateTracker(): KeyStateTracker;
|
|
104
|
-
//#endregion
|
|
102
|
+
export declare function getKeyStateTracker(): KeyStateTracker;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { MODIFIER_KEYS, normalizeKeyName } from "./constants.js";
|
|
2
1
|
import { createStore } from "./_store.js";
|
|
2
|
+
import { MODIFIER_KEYS, normalizeKeyName } from "./constants.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// src/key-state-tracker.ts
|
|
5
5
|
/**
|
|
6
6
|
* Returns the default state for KeyStateTracker.
|
|
7
7
|
*/
|
|
@@ -252,5 +252,4 @@ function getKeyStateTracker() {
|
|
|
252
252
|
return KeyStateTracker.getInstance();
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
//#endregion
|
|
256
255
|
export { KeyStateTracker, getKeyStateTracker };
|
package/dist/key.types.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { LOGICAL_ONLY_NAMED_KEYS, SHARED_NAMED_KEYS } from "./_named-keys.js";
|
|
2
|
-
//#region src/key.types.d.ts
|
|
3
2
|
/**
|
|
4
3
|
* All supported modifier key names, including aliases.
|
|
5
4
|
* - Control/Ctrl: The Control key
|
|
@@ -44,12 +43,13 @@ export type NamedKey = (typeof SHARED_NAMED_KEYS)[number] | (typeof LOGICAL_ONLY
|
|
|
44
43
|
export type NonPunctuationKey = LetterKey | NumberKey | EditingKey | NavigationKey | FunctionKey | NamedKey;
|
|
45
44
|
/**
|
|
46
45
|
* Supported physical KeyboardEvent.code names, independent of keyboard layout.
|
|
47
|
-
* Letter, digit,
|
|
48
|
-
* `
|
|
46
|
+
* Letter, digit, and numpad names use finite template unions. Modifier codes
|
|
47
|
+
* such as `ShiftLeft` are excluded, because modifier-only hotkeys aren't
|
|
48
|
+
* supported. `Unidentified` is excluded because it cannot identify a physical key.
|
|
49
49
|
*
|
|
50
50
|
* @see https://www.w3.org/TR/uievents-code/
|
|
51
51
|
*/
|
|
52
|
-
export type PhysicalKeyCode = `Key${LetterKey}` | `Digit${NumberKey}` | `Numpad${NumberKey}` |
|
|
52
|
+
export type PhysicalKeyCode = `Key${LetterKey}` | `Digit${NumberKey}` | `Numpad${NumberKey}` | EditingKey | NavigationKey | FunctionKey | (typeof SHARED_NAMED_KEYS)[number] | 'Backquote' | 'Backslash' | 'BracketLeft' | 'BracketRight' | 'Comma' | 'Equal' | 'IntlBackslash' | 'IntlRo' | 'IntlYen' | 'Minus' | 'Period' | 'Quote' | 'Semicolon' | 'Slash' | `Lang${1 | 2 | 3 | 4 | 5}` | `Numpad${'Add' | 'Backspace' | 'Clear' | 'ClearEntry' | 'Comma' | 'Decimal' | 'Divide' | 'Enter' | 'Equal' | 'Hash' | 'MemoryAdd' | 'MemoryClear' | 'MemoryRecall' | 'MemoryStore' | 'MemorySubtract' | 'Multiply' | 'ParenLeft' | 'ParenRight' | 'Star' | 'Subtract'}` | 'LaunchApp1' | 'LaunchApp2' | 'MediaSelect' | 'Sleep' | 'Turbo' | 'Abort' | 'Resume' | 'Suspend';
|
|
53
53
|
/**
|
|
54
54
|
* An explicit physical key token. All codes use brackets, including names such
|
|
55
55
|
* as `[Enter]` that also exist as logical keys. Invalid code names are rejected
|
|
@@ -75,5 +75,4 @@ export interface NormalizedKeyboardEvent {
|
|
|
75
75
|
altGraph: boolean;
|
|
76
76
|
location: number;
|
|
77
77
|
isComposing: boolean;
|
|
78
|
-
}
|
|
79
|
-
//#endregion
|
|
78
|
+
}
|
package/dist/match.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { HotkeyCallback, HotkeyChord, HotkeyChordCallbackContext, ParsedHotkeyChord, RegisterableHotkey, RegisterableHotkeySequence } from "./hotkey.types.js";
|
|
2
1
|
import { HotkeyPlatform } from "./platform.js";
|
|
3
|
-
|
|
2
|
+
import { HotkeyCallback, HotkeyChord, HotkeyChordCallbackContext, ParsedHotkeyChord, RegisterableHotkey, RegisterableHotkeySequence } from "./hotkey.types.js";
|
|
4
3
|
export interface KeyboardEventMatch {
|
|
5
4
|
matched: boolean;
|
|
6
5
|
score: 0 | 1 | 2 | 3;
|
|
@@ -22,7 +21,8 @@ export interface KeyboardEventMatch {
|
|
|
22
21
|
* Also handles "dead key" events where `event.key` is `'Dead'` instead of the expected
|
|
23
22
|
* character. This commonly occurs on macOS with Option+letter combinations (e.g., Option+E,
|
|
24
23
|
* Option+I, Option+U, Option+N) and on Windows/Linux with international keyboard layouts.
|
|
25
|
-
* In these cases, `event.code` is used to determine the physical key.
|
|
24
|
+
* In these cases, `event.code` is used to determine the physical key. An
|
|
25
|
+
* `'Unidentified'` key also falls back to `code`, except on letter keys.
|
|
26
26
|
*
|
|
27
27
|
* @param event - The KeyboardEvent to check
|
|
28
28
|
* @param chord - The chord string or parsed chord to match against
|
|
@@ -129,5 +129,4 @@ export declare function createSequenceMatcher(sequence: RegisterableHotkeySequen
|
|
|
129
129
|
match: (event: KeyboardEvent) => boolean;
|
|
130
130
|
reset: () => void;
|
|
131
131
|
getProgress: () => number;
|
|
132
|
-
};
|
|
133
|
-
//#endregion
|
|
132
|
+
};
|
package/dist/match.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { normalizeKeyName } from "./constants.js";
|
|
2
|
-
import { detectPlatform } from "./platform.js";
|
|
3
1
|
import { normalizeKeyboardEvent } from "./_keyboard-event.js";
|
|
4
|
-
import { isHotkeySequence, isModifierKey, parseHotkey } from "./parse.js";
|
|
5
|
-
import { formatHotkey } from "./format.js";
|
|
6
2
|
import { matchKeyboardEvent, parsedChordsEqual } from "./_match.js";
|
|
7
3
|
import { chordHasKey } from "./_registration.js";
|
|
4
|
+
import { normalizeKeyName } from "./constants.js";
|
|
5
|
+
import { formatHotkey } from "./format.js";
|
|
6
|
+
import { isHotkeySequence, isModifierKey, parseHotkey } from "./parse.js";
|
|
7
|
+
import { detectPlatform } from "./platform.js";
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
// src/match.ts
|
|
10
10
|
/**
|
|
11
11
|
* Checks if a KeyboardEvent matches a hotkey.
|
|
12
12
|
*
|
|
@@ -19,7 +19,8 @@ import { chordHasKey } from "./_registration.js";
|
|
|
19
19
|
* Also handles "dead key" events where `event.key` is `'Dead'` instead of the expected
|
|
20
20
|
* character. This commonly occurs on macOS with Option+letter combinations (e.g., Option+E,
|
|
21
21
|
* Option+I, Option+U, Option+N) and on Windows/Linux with international keyboard layouts.
|
|
22
|
-
* In these cases, `event.code` is used to determine the physical key.
|
|
22
|
+
* In these cases, `event.code` is used to determine the physical key. An
|
|
23
|
+
* `'Unidentified'` key also falls back to `code`, except on letter keys.
|
|
23
24
|
*
|
|
24
25
|
* @param event - The KeyboardEvent to check
|
|
25
26
|
* @param chord - The chord string or parsed chord to match against
|
|
@@ -193,5 +194,4 @@ function createSequenceMatcher(sequence, options = {}) {
|
|
|
193
194
|
};
|
|
194
195
|
}
|
|
195
196
|
|
|
196
|
-
//#endregion
|
|
197
197
|
export { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, matchesKeyboardEvent };
|
package/dist/parse.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Key } from "./key.types.js";
|
|
2
1
|
import { Hotkey, HotkeyChord, HotkeySequence, ParsedHotkeyChord, RegisterableHotkey, RegisterableHotkeyChord, RegisterableHotkeySequence } from "./hotkey.types.js";
|
|
3
|
-
|
|
2
|
+
import { Key } from "./key.types.js";
|
|
4
3
|
type Platform = 'mac' | 'windows' | 'linux';
|
|
5
4
|
/** A chord in any form: a string, a chord object, or an already-parsed chord. */
|
|
6
5
|
type AnyChord = RegisterableHotkeyChord | ParsedHotkeyChord | (string & {});
|
|
@@ -103,4 +102,4 @@ export declare function parseKeyboardEvent(event: KeyboardEvent, platform?: Plat
|
|
|
103
102
|
* ```
|
|
104
103
|
*/
|
|
105
104
|
export declare function hasNonModifierKey(chord: HotkeyChord | ParsedHotkeyChord | (string & {}), platform?: Platform): boolean;
|
|
106
|
-
|
|
105
|
+
export {};
|
package/dist/parse.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { assertLogicalKey, modifierAlias, normalizeKeyboardEvent, physicalCodeOf, splitChordParts } from "./_keyboard-event.js";
|
|
2
|
+
import { chordHasKey } from "./_registration.js";
|
|
1
3
|
import { MODIFIER_ORDER, normalizeKeyName } from "./constants.js";
|
|
2
4
|
import { detectPlatform, resolveModifier } from "./platform.js";
|
|
3
|
-
import { assertLogicalKey, modifierAlias, normalizeKeyboardEvent, physicalCodeOf, splitChordParts } from "./_keyboard-event.js";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
// src/parse.ts
|
|
6
7
|
/** Builds a ParsedHotkeyChord, listing held modifiers in canonical order. */
|
|
7
8
|
function toParsedChord(identity, ctrl, shift, alt, meta) {
|
|
8
9
|
const held = {
|
|
@@ -31,21 +32,14 @@ function simplifyHotkey(hotkey) {
|
|
|
31
32
|
return isHotkeySequence(hotkey) && hotkey.length === 1 ? hotkey[0] : hotkey;
|
|
32
33
|
}
|
|
33
34
|
function parseChordString(chord, platform) {
|
|
34
|
-
const parts = splitChordParts(chord);
|
|
35
|
+
const parts = splitChordParts(chord).map((part) => part.trim());
|
|
36
|
+
const key = normalizeKeyName(parts.pop());
|
|
35
37
|
const modifiers = /* @__PURE__ */ new Set();
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
else {
|
|
41
|
-
const alias = modifierAlias(part);
|
|
42
|
-
if (alias) {
|
|
43
|
-
const resolved = resolveModifier(alias, platform);
|
|
44
|
-
modifiers.add(resolved);
|
|
45
|
-
} else if (parts.length === 1) key = normalizeKeyName(part);
|
|
46
|
-
}
|
|
38
|
+
for (const part of parts) {
|
|
39
|
+
const alias = modifierAlias(part);
|
|
40
|
+
if (!alias) return toParsedChord({ key: "" }, false, false, false, false);
|
|
41
|
+
modifiers.add(resolveModifier(alias, platform));
|
|
47
42
|
}
|
|
48
|
-
if (!key && parts.length > 0) key = normalizeKeyName(parts[parts.length - 1].trim());
|
|
49
43
|
const code = physicalCodeOf(key);
|
|
50
44
|
return toParsedChord(code !== void 0 ? { code } : { key }, modifiers.has("Control"), modifiers.has("Shift"), modifiers.has("Alt"), modifiers.has("Meta"));
|
|
51
45
|
}
|
|
@@ -145,10 +139,7 @@ function parseKeyboardEvent(event, platform) {
|
|
|
145
139
|
* ```
|
|
146
140
|
*/
|
|
147
141
|
function hasNonModifierKey(chord, platform = detectPlatform()) {
|
|
148
|
-
|
|
149
|
-
if (parsed.code !== void 0) return parsed.code.length > 0 && !/^(Control|Shift|Alt|Meta)(Left|Right)$/.test(parsed.code);
|
|
150
|
-
return !isModifierKey(parsed.key) && parsed.key.length > 0;
|
|
142
|
+
return chordHasKey(typeof chord === "string" ? parseChordString(chord, platform) : chord);
|
|
151
143
|
}
|
|
152
144
|
|
|
153
|
-
//#endregion
|
|
154
145
|
export { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey, parseHotkey, parseKeyboardEvent, simplifyHotkey };
|
package/dist/platform.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { CanonicalModifier } from "./key.types.js";
|
|
2
|
-
//#region src/platform.d.ts
|
|
3
2
|
/** A platform for resolving `Mod` and formatting labels. */
|
|
4
3
|
export type HotkeyPlatform = 'mac' | 'windows' | 'linux';
|
|
5
4
|
/**
|
|
@@ -49,5 +48,4 @@ export declare function detectPlatform(userAgent?: string | null): HotkeyPlatfor
|
|
|
49
48
|
* resolveModifier('Control', 'mac') // 'Control' (unchanged)
|
|
50
49
|
* ```
|
|
51
50
|
*/
|
|
52
|
-
export declare function resolveModifier(modifier: CanonicalModifier | 'Mod', platform?: 'mac' | 'windows' | 'linux'): CanonicalModifier;
|
|
53
|
-
//#endregion
|
|
51
|
+
export declare function resolveModifier(modifier: CanonicalModifier | 'Mod', platform?: 'mac' | 'windows' | 'linux'): CanonicalModifier;
|
package/dist/platform.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isServerRuntime } from "./_server.js";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// src/platform.ts
|
|
4
4
|
/**
|
|
5
5
|
* Detects a platform from a user agent string, or from the browser's
|
|
6
6
|
* `navigator` when called without one.
|
|
@@ -65,5 +65,4 @@ function resolveModifier(modifier, platform = detectPlatform()) {
|
|
|
65
65
|
return modifier;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
//#endregion
|
|
69
68
|
export { detectPlatform, resolveModifier };
|
package/dist/validate.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Hotkey } from "./hotkey.types.js";
|
|
2
|
-
//#region src/validate.d.ts
|
|
3
2
|
/** A hotkey to validate: a chord string, a sequence, or untyped input such as saved data. */
|
|
4
3
|
export type ValidatableHotkey = Hotkey | (string & {}) | ReadonlyArray<string>;
|
|
5
4
|
/**
|
|
6
5
|
* Validates a hotkey and returns any warnings or errors.
|
|
7
|
-
*
|
|
6
|
+
* Each issue has a `reason` code, so apps can write their own messages.
|
|
7
|
+
* Issues in a sequence carry the index of their `step`.
|
|
8
8
|
*
|
|
9
9
|
* Checks for:
|
|
10
10
|
* - Valid syntax (modifier+...+key format)
|
|
11
11
|
* - Known modifiers
|
|
12
|
+
* - A key that isn't a modifier
|
|
12
13
|
* - Known keys
|
|
13
14
|
*
|
|
14
15
|
* @param hotkey - The hotkey string to validate
|
|
@@ -20,10 +21,10 @@ export type ValidatableHotkey = Hotkey | (string & {}) | ReadonlyArray<string>;
|
|
|
20
21
|
* // { valid: true, warnings: [], errors: [] }
|
|
21
22
|
*
|
|
22
23
|
* validateHotkey('')
|
|
23
|
-
* // { valid: false, warnings: [], errors: [
|
|
24
|
+
* // { valid: false, warnings: [], errors: [{ reason: 'empty' }] }
|
|
24
25
|
*
|
|
25
26
|
* validateHotkey(['G', 'Foo+H'])
|
|
26
|
-
* // { valid: false, warnings: [], errors: [
|
|
27
|
+
* // { valid: false, warnings: [], errors: [{ reason: 'unknown-modifier', part: 'Foo', step: 1 }] }
|
|
27
28
|
* ```
|
|
28
29
|
*/
|
|
29
30
|
export declare function validateHotkey(hotkey: ValidatableHotkey): ValidationResult;
|
|
@@ -37,7 +38,7 @@ export declare function validateHotkey(hotkey: ValidatableHotkey): ValidationRes
|
|
|
37
38
|
* @example
|
|
38
39
|
* ```ts
|
|
39
40
|
* assertValidHotkey('Mod+S') // OK
|
|
40
|
-
* assertValidHotkey('') // Throws Error: Invalid hotkey:
|
|
41
|
+
* assertValidHotkey('') // Throws Error: [hotkeys] Invalid hotkey '': empty
|
|
41
42
|
* ```
|
|
42
43
|
*/
|
|
43
44
|
export declare function assertValidHotkey(hotkey: ValidatableHotkey): void;
|
|
@@ -51,24 +52,43 @@ export declare function assertValidHotkey(hotkey: ValidatableHotkey): void;
|
|
|
51
52
|
* @example
|
|
52
53
|
* ```ts
|
|
53
54
|
* checkHotkey('Control+escape')
|
|
54
|
-
* // Console: Hotkey 'Control+escape'
|
|
55
|
+
* // Console: [hotkeys] Hotkey 'Control+escape' may never fire: unknown-key 'escape'
|
|
55
56
|
* // Returns: true
|
|
56
57
|
*
|
|
57
58
|
* checkHotkey('Ctl+K')
|
|
58
|
-
* // Console:
|
|
59
|
+
* // Console: [hotkeys] Invalid hotkey 'Ctl+K': unknown-modifier 'Ctl'
|
|
59
60
|
* // Returns: false
|
|
60
61
|
* ```
|
|
61
62
|
*/
|
|
62
63
|
export declare function checkHotkey(hotkey: ValidatableHotkey): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Why a hotkey is invalid or may never fire:
|
|
66
|
+
*
|
|
67
|
+
* - `'empty'`: the hotkey or sequence is empty.
|
|
68
|
+
* - `'empty-part'`: a part between `+` signs is empty or whitespace.
|
|
69
|
+
* - `'unknown-modifier'`: a modifier isn't one the library knows, such as `Ctl`.
|
|
70
|
+
* - `'invalid-physical-key'`: a bracketed key isn't a `KeyboardEvent.code`.
|
|
71
|
+
* - `'modifier-only'`: the key is a modifier, such as `Shift` or `[ShiftLeft]`.
|
|
72
|
+
* - `'unknown-key'` (warning): the key isn't written like a known key name.
|
|
73
|
+
* Key names are case-sensitive, so `escape` never matches `Escape`.
|
|
74
|
+
*/
|
|
75
|
+
export type HotkeyIssueReason = 'empty' | 'empty-part' | 'unknown-modifier' | 'invalid-physical-key' | 'modifier-only' | 'unknown-key';
|
|
76
|
+
/** One problem found by `validateHotkey`. */
|
|
77
|
+
export interface HotkeyIssue {
|
|
78
|
+
reason: HotkeyIssueReason;
|
|
79
|
+
/** The part of the chord with the problem, such as `'Ctl'` in `'Ctl+K'`. */
|
|
80
|
+
part?: string;
|
|
81
|
+
/** For a sequence, the index of the step with the problem. */
|
|
82
|
+
step?: number;
|
|
83
|
+
}
|
|
63
84
|
/**
|
|
64
85
|
* Result of validating a hotkey string.
|
|
65
86
|
*/
|
|
66
87
|
export interface ValidationResult {
|
|
67
88
|
/** Whether the hotkey is valid (can still have warnings) */
|
|
68
89
|
valid: boolean;
|
|
69
|
-
/**
|
|
70
|
-
warnings: Array<
|
|
71
|
-
/**
|
|
72
|
-
errors: Array<
|
|
73
|
-
}
|
|
74
|
-
//#endregion
|
|
90
|
+
/** Problems that may stop the hotkey from firing, such as an unknown key */
|
|
91
|
+
warnings: Array<HotkeyIssue>;
|
|
92
|
+
/** Problems that stop the hotkey from registering */
|
|
93
|
+
errors: Array<HotkeyIssue>;
|
|
94
|
+
}
|
package/dist/validate.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { isKeyNameShape, modifierAlias, physicalCodeOf, splitChordParts } from "./_keyboard-event.js";
|
|
1
|
+
import { isKeyNameShape, isModifierCode, modifierAlias, physicalCodeOf, splitChordParts } from "./_keyboard-event.js";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// src/validate.ts
|
|
4
4
|
/**
|
|
5
5
|
* Validates a hotkey and returns any warnings or errors.
|
|
6
|
-
*
|
|
6
|
+
* Each issue has a `reason` code, so apps can write their own messages.
|
|
7
|
+
* Issues in a sequence carry the index of their `step`.
|
|
7
8
|
*
|
|
8
9
|
* Checks for:
|
|
9
10
|
* - Valid syntax (modifier+...+key format)
|
|
10
11
|
* - Known modifiers
|
|
12
|
+
* - A key that isn't a modifier
|
|
11
13
|
* - Known keys
|
|
12
14
|
*
|
|
13
15
|
* @param hotkey - The hotkey string to validate
|
|
@@ -19,55 +21,71 @@ import { isKeyNameShape, modifierAlias, physicalCodeOf, splitChordParts } from "
|
|
|
19
21
|
* // { valid: true, warnings: [], errors: [] }
|
|
20
22
|
*
|
|
21
23
|
* validateHotkey('')
|
|
22
|
-
* // { valid: false, warnings: [], errors: [
|
|
24
|
+
* // { valid: false, warnings: [], errors: [{ reason: 'empty' }] }
|
|
23
25
|
*
|
|
24
26
|
* validateHotkey(['G', 'Foo+H'])
|
|
25
|
-
* // { valid: false, warnings: [], errors: [
|
|
27
|
+
* // { valid: false, warnings: [], errors: [{ reason: 'unknown-modifier', part: 'Foo', step: 1 }] }
|
|
26
28
|
* ```
|
|
27
29
|
*/
|
|
28
30
|
function validateHotkey(hotkey) {
|
|
29
31
|
if (typeof hotkey !== "string") {
|
|
30
|
-
if (hotkey.length === 0) return
|
|
31
|
-
valid: false,
|
|
32
|
-
warnings: [],
|
|
33
|
-
errors: ["Sequence cannot be empty"]
|
|
34
|
-
};
|
|
32
|
+
if (hotkey.length === 0) return invalid("empty");
|
|
35
33
|
if (hotkey.length === 1) return validateChord(hotkey[0]);
|
|
36
34
|
const results = hotkey.map(validateChord);
|
|
37
|
-
const
|
|
35
|
+
const withStep = (key) => results.flatMap((result, step) => result[key].map((issue) => ({
|
|
36
|
+
...issue,
|
|
37
|
+
step
|
|
38
|
+
})));
|
|
38
39
|
return {
|
|
39
40
|
valid: results.every((result) => result.valid),
|
|
40
|
-
warnings:
|
|
41
|
-
errors:
|
|
41
|
+
warnings: withStep("warnings"),
|
|
42
|
+
errors: withStep("errors")
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
return validateChord(hotkey);
|
|
45
46
|
}
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
const errors = [];
|
|
49
|
-
if (!hotkey || hotkey.trim() === "") return {
|
|
47
|
+
function invalid(reason) {
|
|
48
|
+
return {
|
|
50
49
|
valid: false,
|
|
51
50
|
warnings: [],
|
|
52
|
-
errors: [
|
|
51
|
+
errors: [{ reason }]
|
|
53
52
|
};
|
|
53
|
+
}
|
|
54
|
+
function validateChord(hotkey) {
|
|
55
|
+
const warnings = [];
|
|
56
|
+
const errors = [];
|
|
57
|
+
if (!hotkey || hotkey.trim() === "") return invalid("empty");
|
|
54
58
|
const parts = splitChordParts(hotkey).map((p) => p.trim());
|
|
55
|
-
if (parts.length === 0 || parts.some((p) => p === "")) return
|
|
56
|
-
valid: false,
|
|
57
|
-
warnings: [],
|
|
58
|
-
errors: ["Invalid hotkey format: empty parts detected"]
|
|
59
|
-
};
|
|
59
|
+
if (parts.length === 0 || parts.some((p) => p === "")) return invalid("empty-part");
|
|
60
60
|
const modifierParts = parts.slice(0, -1);
|
|
61
61
|
const keyPart = parts[parts.length - 1];
|
|
62
|
-
for (const modifier of modifierParts) if (!modifierAlias(modifier)) errors.push(
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
for (const modifier of modifierParts) if (!modifierAlias(modifier)) errors.push({
|
|
63
|
+
reason: "unknown-modifier",
|
|
64
|
+
part: modifier
|
|
65
|
+
});
|
|
66
|
+
const code = physicalCodeOf(keyPart);
|
|
67
|
+
if (keyPart.length > 1 && (keyPart.startsWith("[") || keyPart.endsWith("]")) && code === void 0) errors.push({
|
|
68
|
+
reason: "invalid-physical-key",
|
|
69
|
+
part: keyPart
|
|
70
|
+
});
|
|
71
|
+
if (code !== void 0 ? isModifierCode(code) : modifierAlias(keyPart)) errors.push({
|
|
72
|
+
reason: "modifier-only",
|
|
73
|
+
part: keyPart
|
|
74
|
+
});
|
|
75
|
+
if (code === void 0 && !isKeyNameShape(keyPart)) warnings.push({
|
|
76
|
+
reason: "unknown-key",
|
|
77
|
+
part: keyPart
|
|
78
|
+
});
|
|
65
79
|
return {
|
|
66
80
|
valid: errors.length === 0,
|
|
67
81
|
warnings,
|
|
68
82
|
errors
|
|
69
83
|
};
|
|
70
84
|
}
|
|
85
|
+
/** Lists issues for a console message, such as `unknown-modifier 'Ctl'`. */
|
|
86
|
+
function describeIssues(issues) {
|
|
87
|
+
return issues.map(({ reason, part, step }) => (step === void 0 ? "" : `step ${step + 1} `) + reason + (part === void 0 ? "" : ` '${part}'`)).join(", ");
|
|
88
|
+
}
|
|
71
89
|
/**
|
|
72
90
|
* Validates a hotkey and throws an error if invalid.
|
|
73
91
|
* Useful for development-time validation.
|
|
@@ -78,12 +96,12 @@ function validateChord(hotkey) {
|
|
|
78
96
|
* @example
|
|
79
97
|
* ```ts
|
|
80
98
|
* assertValidHotkey('Mod+S') // OK
|
|
81
|
-
* assertValidHotkey('') // Throws Error: Invalid hotkey:
|
|
99
|
+
* assertValidHotkey('') // Throws Error: [hotkeys] Invalid hotkey '': empty
|
|
82
100
|
* ```
|
|
83
101
|
*/
|
|
84
102
|
function assertValidHotkey(hotkey) {
|
|
85
103
|
const result = validateHotkey(hotkey);
|
|
86
|
-
if (!result.valid) throw new Error(`Invalid hotkey '${String(hotkey)}': ${result.errors
|
|
104
|
+
if (!result.valid) throw new Error(`[hotkeys] Invalid hotkey '${String(hotkey)}': ${describeIssues(result.errors)}`);
|
|
87
105
|
}
|
|
88
106
|
/**
|
|
89
107
|
* Validates a hotkey and logs errors and warnings to the console.
|
|
@@ -95,22 +113,21 @@ function assertValidHotkey(hotkey) {
|
|
|
95
113
|
* @example
|
|
96
114
|
* ```ts
|
|
97
115
|
* checkHotkey('Control+escape')
|
|
98
|
-
* // Console: Hotkey 'Control+escape'
|
|
116
|
+
* // Console: [hotkeys] Hotkey 'Control+escape' may never fire: unknown-key 'escape'
|
|
99
117
|
* // Returns: true
|
|
100
118
|
*
|
|
101
119
|
* checkHotkey('Ctl+K')
|
|
102
|
-
* // Console:
|
|
120
|
+
* // Console: [hotkeys] Invalid hotkey 'Ctl+K': unknown-modifier 'Ctl'
|
|
103
121
|
* // Returns: false
|
|
104
122
|
* ```
|
|
105
123
|
*/
|
|
106
124
|
function checkHotkey(hotkey) {
|
|
107
125
|
const result = validateHotkey(hotkey);
|
|
108
|
-
if (process.env.NODE_ENV !== "production") {
|
|
109
|
-
if (result.errors.length > 0) console.error(`
|
|
110
|
-
if (result.warnings.length > 0) console.warn(`Hotkey '${String(hotkey)}'
|
|
126
|
+
if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
|
|
127
|
+
if (result.errors.length > 0) console.error(`[hotkeys] Invalid hotkey '${String(hotkey)}': ${describeIssues(result.errors)}`);
|
|
128
|
+
if (result.warnings.length > 0) console.warn(`[hotkeys] Hotkey '${String(hotkey)}' may never fire: ${describeIssues(result.warnings)}`);
|
|
111
129
|
}
|
|
112
130
|
return result.valid;
|
|
113
131
|
}
|
|
114
132
|
|
|
115
|
-
//#endregion
|
|
116
133
|
export { assertValidHotkey, checkHotkey, validateHotkey };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Observer, Subscription } from "./types.js";
|
|
2
|
-
//#region ../../node_modules/.pnpm/@tanstack+store@0.11.2/node_modules/@tanstack/store/dist/store.d.ts
|
|
3
2
|
//#region src/store.d.ts
|
|
4
3
|
type StoreAction = (...args: Array<any>) => any;
|
|
5
4
|
type StoreActionMap = Record<string, StoreAction>;
|
|
@@ -19,5 +18,4 @@ declare class Store<T, TActions extends StoreActionMap = never> {
|
|
|
19
18
|
get(): T;
|
|
20
19
|
subscribe(observerOrFn: Observer<T> | ((value: T) => void)): Subscription;
|
|
21
20
|
}
|
|
22
|
-
//#endregion
|
|
23
21
|
export { Store, StoreAction, StoreActionMap, StoreActionsFactory };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//#region ../../node_modules/.pnpm/@tanstack+store@0.11.2/node_modules/@tanstack/store/dist/types.d.ts
|
|
2
1
|
type Observer<T> = {
|
|
3
2
|
next?: (value: T) => void;
|
|
4
3
|
error?: (err: unknown) => void;
|
|
@@ -7,5 +6,4 @@ type Observer<T> = {
|
|
|
7
6
|
interface Subscription {
|
|
8
7
|
unsubscribe: () => void;
|
|
9
8
|
}
|
|
10
|
-
//#endregion
|
|
11
9
|
export { Observer, Subscription };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/hotkeys",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Type-safe, framework-agnostic keyboard hotkey management for the browser",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"clean": "premove ./build ./dist",
|
|
50
|
-
"lint": "
|
|
51
|
-
"lint:fix": "
|
|
52
|
-
"test:
|
|
50
|
+
"lint": "oxlint ./src",
|
|
51
|
+
"lint:fix": "oxlint ./src --fix",
|
|
52
|
+
"test:oxlint": "oxlint ./src",
|
|
53
53
|
"test:lib": "vitest",
|
|
54
54
|
"test:lib:dev": "pnpm test:lib --watch",
|
|
55
55
|
"test:types": "tsc",
|
|
@@ -52,7 +52,7 @@ Augment `Register` in the adapter module you import from, such as `declare modul
|
|
|
52
52
|
|
|
53
53
|
- **Register the app hotkey, not its value.** Pass `appHotkeys['doc.save']`. Passing `.hotkey` registers the declared default, so the user's rebinding never applies, and the list reports the shortcut as `'inactive'`.
|
|
54
54
|
- **Save what `onCustomHotkeysChange` receives.** It holds only the shortcuts the user changed, so users still get new defaults. Saving every effective hotkey freezes today's defaults into their data.
|
|
55
|
-
- **Ids are a storage contract.** Saved data is keyed by id, and unknown ids are dropped
|
|
55
|
+
- **Ids are a storage contract.** Saved data is keyed by id, and unknown ids are silently dropped, so renaming an id discards users' customizations.
|
|
56
56
|
- **`setCustomHotkey` returns conflicts and changes nothing when there are any.** Check the result before reporting success, or reject the key press earlier by calling `findConflicts` in the recorder's `validate`.
|
|
57
57
|
- **Declare scopes on app hotkeys that share keys.** An app hotkey without a scope, or in `'global'`, conflicts with every other app hotkey on the same keys, so rebinding is rejected.
|
|
58
58
|
- **Conflict checks treat physical and logical bindings as different.** A recorded `Mod+[KeyP]` doesn't conflict with a declared `Mod+P`, although Command+P runs both. Declaring rebindable defaults in the recorder's form, such as `Mod+[KeyP]`, makes them comparable.
|
|
@@ -59,10 +59,12 @@ When nesting scopes, stacking dialogs, or keeping some hotkeys working during an
|
|
|
59
59
|
- **A disabled hotkey doesn't block the browser.** With `enabled: false`, `Mod+S` opens the Save Page dialog. Add `preventDefault: 'always'` to keep the action blocked while the hotkey can't fire, whether it's disabled or its scope is off. Skip it for hotkeys turned off to give the key back to the browser, such as `Mod+C`, `Mod+Z`, `Tab`, or single keys behind a user's off switch. Don't keep the hotkey enabled and return early from the callback; the hotkey would also stay `active` in app hotkey lists and show its hint.
|
|
60
60
|
- **Modifiers match exactly.** `ArrowDown` never fires while Shift is held, so register `Shift+ArrowDown` instead of checking `event.shiftKey`. Shift that a symbol needs is the exception: `?` matches Shift+/.
|
|
61
61
|
- **Chords repeat while held.** Set `requireReset: true` on toggles, or holding the keys flickers them.
|
|
62
|
-
- **Key names are case-sensitive.** Write `Escape`, `ArrowUp`, `F1`, and `+` as the types spell them; `escape`, `Esc`, `f1`, and `Plus` never match. Only letters match in any case. Hotkeys from plain JavaScript or saved data skip the types, so check them with `validateHotkey`.
|
|
62
|
+
- **Key names are case-sensitive.** Write `Escape`, `ArrowUp`, `F1`, and `+` as the types spell them; `escape`, `Esc`, `f1`, and `Plus` never match. Only letters match in any case. Hotkeys from plain JavaScript or saved data skip the types, so check them with `validateHotkey`. Its errors and warnings are reason codes such as `{ reason: 'unknown-key', part: 'escape' }`, not text, so map them to your own messages. A modifier-only hotkey, or one with an unknown modifier such as `Ctl+K`, registers nothing.
|
|
63
63
|
- **Letters follow the typed character.** For position-based controls such as WASD, use physical bindings such as `'[KeyW]'`. Keep letters for mnemonic commands such as `Mod+S`.
|
|
64
64
|
- **Each open exclusive scope needs its own name.** A reusable dialog with a fixed scope name breaks when one dialog opens another: both share one scope and both handle `Escape`. Build the name per instance.
|
|
65
65
|
- **A chord on a sequence's first key runs every time the sequence starts.** With `G` and `['G', 'G']`, the first `G` runs the chord. Later keys belong to the sequence. To show "waiting for the next key", read `matchedStepCount` from the adapter's registrations list.
|
|
66
|
+
- **A sequence that starts a longer one doesn't wait for it.** With `['G', 'G']` and `['G', 'G', 'G']`, three G presses run both, with no warning. Pick sequences where neither one starts the other.
|
|
67
|
+
- **Component libraries handle Escape too.** A global `Escape` hotkey can run alongside a library's dropdown or dialog closing, or keep a library's overlay open. Native modal dialogs and popovers get Escape on their own, except `popover="manual"`: hotkeys outside them skip it. Set `ignoreDefaultPrevented: true` in the adapter's shared defaults (on each hotkey in Lit) for libraries that call `preventDefault()` before the hotkey runs, such as Radix UI and shadcn/ui in React. The option can't see a `preventDefault()` that comes after the hotkey, as in Bits UI, so give open overlays an exclusive scope for those and the rest. The sensible defaults guide lists libraries per framework.
|
|
66
68
|
- **Single-character shortcuts need an off switch.** For WCAG 2.1.4, `K`, `?`, and `['G', 'H']` need a user setting passed as `enabled`, or an app hotkey users can remap.
|
|
67
69
|
- **react-hotkeys-hook names don't carry over.** `useHotkeys` and `HotkeysProvider` share names, not signatures: there's no dependency array, `preventDefault` is on by default, and sequences are arrays. Remove the old library, so two libraries don't handle the same keys.
|
|
68
70
|
- **Install only the adapter.** A separately installed `@tanstack/hotkeys` at another version is a second copy, and scopes don't apply across copies.
|