@tanstack/hotkeys 0.15.1 → 0.16.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.
@@ -37,7 +37,7 @@ const initialState = {
37
37
  * })
38
38
  *
39
39
  * const sequenceRecorder = new HotkeyRecorder({
40
- * maxSteps: 3,
40
+ * maxSteps: Infinity,
41
41
  * onRecord: (hotkey) => {
42
42
  * console.log('Recorded:', hotkey) // 'Mod+S' or ['G', 'H']
43
43
  * },
@@ -113,7 +113,8 @@ var HotkeyRecorder = class {
113
113
  if (!this.#keydownHandler) return;
114
114
  if (this.#options.ignoreInputs !== false && event.key !== "Escape" && isTypingEvent(event, document)) return;
115
115
  const platform = this.#options.platform ?? this.#platform;
116
- if (normalizeKeyboardEvent(event, platform).isComposing) return;
116
+ const normalized = normalizeKeyboardEvent(event, platform);
117
+ if (normalized.isComposing) return;
117
118
  captureRecordingEvent(event);
118
119
  event.preventDefault();
119
120
  event.stopPropagation();
@@ -122,7 +123,7 @@ var HotkeyRecorder = class {
122
123
  this.cancel();
123
124
  return;
124
125
  }
125
- const unmodified = !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey;
126
+ const unmodified = !normalized.ctrl && !normalized.shift && !normalized.alt && !normalized.meta && !normalized.altGraph;
126
127
  const multiStep = this.#maxSteps > 1;
127
128
  if ((event.key === "Backspace" || event.key === "Delete") && unmodified) {
128
129
  if (this.store.state.steps.length === 0) {
@@ -198,13 +199,17 @@ var HotkeyRecorder = class {
198
199
  }
199
200
  options.onReject?.(rejection);
200
201
  };
201
- const parsedSequence = steps.map((step) => parseHotkey(step, platform));
202
- const accepted = options.validate?.(hotkey, {
202
+ const parsedSequence = parseHotkey(steps, platform);
203
+ const context = steps.length === 1 ? {
204
+ kind: "chord",
203
205
  event: this.#events[this.#events.length - 1],
204
- parsedHotkey: parsedSequence[parsedSequence.length - 1],
206
+ parsedChord: parsedSequence[0]
207
+ } : {
208
+ kind: "sequence",
205
209
  events: [...this.#events],
206
210
  parsedSequence
207
- });
211
+ };
212
+ const accepted = options.validate?.(hotkey, context);
208
213
  if (accepted !== void 0 && accepted !== true) {
209
214
  rejectAndKeepRecording({
210
215
  reason: "validation",
@@ -11,7 +11,7 @@ import { CanonicalModifier, Key, LogicalKey } from "./key.types.js";
11
11
  * This enables cross-platform hotkey definitions that automatically adapt to the platform.
12
12
  * For example, `Mod+S` becomes `Command+S` on Mac and `Ctrl+S` on Windows/Linux.
13
13
  */
14
- export type SingleModifierHotkey = `Control+${Key}` | `Alt+${Key}` | `Shift+${Key}` | `Meta+${Key}` | `Mod+${Key}`;
14
+ export type SingleModifierHotkeyChord = `Control+${Key}` | `Alt+${Key}` | `Shift+${Key}` | `Meta+${Key}` | `Mod+${Key}`;
15
15
  /**
16
16
  * Two modifier + key combinations.
17
17
  *
@@ -21,7 +21,7 @@ export type SingleModifierHotkey = `Control+${Key}` | `Alt+${Key}` | `Shift+${Ke
21
21
  * - `Mod+Control` duplicates `Control` on Windows/Linux (Mod = Control)
22
22
  * - `Mod+Meta` duplicates `Meta` on macOS (Mod = Meta)
23
23
  */
24
- export type TwoModifierHotkey = `Control+Alt+${Key}` | `Control+Shift+${Key}` | `Control+Meta+${Key}` | `Alt+Shift+${Key}` | `Alt+Meta+${Key}` | `Shift+Meta+${Key}` | `Mod+Alt+${Key}` | `Mod+Shift+${Key}`;
24
+ export type TwoModifierHotkeyChord = `Control+Alt+${Key}` | `Control+Shift+${Key}` | `Control+Meta+${Key}` | `Alt+Shift+${Key}` | `Alt+Meta+${Key}` | `Shift+Meta+${Key}` | `Mod+Alt+${Key}` | `Mod+Shift+${Key}`;
25
25
  /**
26
26
  * Three modifier + key combinations.
27
27
  *
@@ -31,7 +31,7 @@ export type TwoModifierHotkey = `Control+Alt+${Key}` | `Control+Shift+${Key}` |
31
31
  * - `Mod+Control+Shift` duplicates `Control` on Windows/Linux (Mod = Control)
32
32
  * - `Mod+Shift+Meta` duplicates `Meta` on macOS (Mod = Meta)
33
33
  */
34
- export type ThreeModifierHotkey = `Control+Alt+Shift+${Key}` | `Control+Alt+Meta+${Key}` | `Control+Shift+Meta+${Key}` | `Alt+Shift+Meta+${Key}` | `Mod+Alt+Shift+${Key}`;
34
+ export type ThreeModifierHotkeyChord = `Control+Alt+Shift+${Key}` | `Control+Alt+Meta+${Key}` | `Control+Shift+Meta+${Key}` | `Alt+Shift+Meta+${Key}` | `Mod+Alt+Shift+${Key}`;
35
35
  /**
36
36
  * Four modifier + key combinations.
37
37
  *
@@ -44,7 +44,7 @@ export type ThreeModifierHotkey = `Control+Alt+Shift+${Key}` | `Control+Alt+Meta
44
44
  * - `Mod+Control+Alt+Shift` → duplicates `Control` on Windows/Linux
45
45
  * - `Mod+Alt+Shift+Meta` → duplicates `Meta` on macOS
46
46
  */
47
- export type FourModifierHotkey = `Control+Alt+Shift+Meta+${Key}`;
47
+ export type FourModifierHotkeyChord = `Control+Alt+Shift+Meta+${Key}`;
48
48
  /**
49
49
  * A type-safe hotkey string.
50
50
  *
@@ -97,7 +97,7 @@ export type FourModifierHotkey = `Control+Alt+Shift+Meta+${Key}`;
97
97
  * const windowsOnly: HotkeyChord = 'Control+S' // Ctrl+S on Windows/Linux only
98
98
  * ```
99
99
  */
100
- export type HotkeyChord = Key | SingleModifierHotkey | TwoModifierHotkey | ThreeModifierHotkey | FourModifierHotkey;
100
+ export type HotkeyChord = Key | SingleModifierHotkeyChord | TwoModifierHotkeyChord | ThreeModifierHotkeyChord | FourModifierHotkeyChord;
101
101
  /** Resolved modifier flags shared by both parsed binding variants. */
102
102
  export interface ParsedModifiers {
103
103
  /** Whether Control is required. */
@@ -112,15 +112,15 @@ export interface ParsedModifiers {
112
112
  modifiers: Array<CanonicalModifier>;
113
113
  }
114
114
  /**
115
- * A parsed binding matches either a logical key or a physical code, never both.
115
+ * A parsed chord matches either a logical key or a physical code, never both.
116
116
  * Check `code !== undefined` to narrow to a physical binding. Its logical
117
117
  * character is unknown without a keyboard event and is not stored in `key`.
118
118
  *
119
119
  * @example
120
120
  * parseHotkey('Alt+S') // { key: 'S', alt: true, ... }
121
- * parseHotkey('Alt+[KeyS]') // { code: 'KeyS', alt: true, ... } — no key property
121
+ * parseHotkey('Alt+[KeyS]') // { code: 'KeyS', alt: true, ... } with no key property
122
122
  */
123
- export type ParsedHotkey = ParsedModifiers & ({
123
+ export type ParsedHotkeyChord = ParsedModifiers & ({
124
124
  key: LogicalKey | (string & {});
125
125
  code?: never;
126
126
  } | {
@@ -141,15 +141,12 @@ export interface RawModifiers {
141
141
  meta?: boolean;
142
142
  }
143
143
  /**
144
- * A raw hotkey object for programmatic registration.
145
- *
146
- * Like `ParsedHotkey` but without `modifiers` (derived from booleans)
147
- * and with optional modifier booleans (default to `false` when omitted).
148
- * Use with `HotkeyManager.register()` and `useHotkey()` when you prefer
149
- * object form over a string.
144
+ * A chord written as an object instead of a string, for building chords from
145
+ * data. Set `key` for a logical key or `code` for a physical one, and set a
146
+ * boolean for each modifier. Omitted modifiers default to `false`.
150
147
  *
151
148
  * The `mod` modifier is platform-adaptive: Command on macOS, Control on Windows/Linux.
152
- * Pass `platform` when converting to ParsedHotkey (e.g., via `options.platform`).
149
+ * Sequence steps can be objects too: `[{ key: 'K', mod: true }, 'C']`.
153
150
  *
154
151
  * @example
155
152
  * ```ts
@@ -162,7 +159,7 @@ export interface RawModifiers {
162
159
  * useHotkey({ code: 'NumpadAdd', mod: true }, handler) // Physical numpad plus
163
160
  * ```
164
161
  */
165
- export type RawHotkey = ({
162
+ export type RawHotkeyChord = ({
166
163
  key: LogicalKey | (string & {});
167
164
  code?: never;
168
165
  } & RawModifiers) | ({
@@ -170,7 +167,9 @@ export type RawHotkey = ({
170
167
  key?: never;
171
168
  } & RawModifiers);
172
169
  /**
173
- * A sequence of chords pressed one after another (Vim-style), such as `['G', 'G']`.
170
+ * A sequence of chord strings pressed one after another (Vim-style), such as
171
+ * `['G', 'G']`. Registered sequences are stored in this form. To register
172
+ * steps written as objects, see {@link RegisterableHotkeySequence}.
174
173
  *
175
174
  * Steps may include modifiers; the same modifier can appear on consecutive
176
175
  * steps (e.g. `['Shift+R', 'Shift+T']`). Modifier-only key events do not
@@ -182,36 +181,64 @@ export type HotkeySequence = ReadonlyArray<HotkeyChord>;
182
181
  * A hotkey: one chord (`'Mod+S'`) or a sequence of chords (`['G', 'G']`).
183
182
  */
184
183
  export type Hotkey = HotkeyChord | HotkeySequence;
185
- /** A single chord as a type-safe string (`HotkeyChord`) or a raw object (`RawHotkey`). */
186
- export type RegisterableHotkeyChord = HotkeyChord | RawHotkey;
184
+ /** A single chord as a type-safe string (`HotkeyChord`) or an object (`RawHotkeyChord`). */
185
+ export type RegisterableHotkeyChord = HotkeyChord | RawHotkeyChord;
187
186
  /**
188
- * Anything that can be registered: a chord string, a raw chord object, or a sequence.
187
+ * A sequence whose steps are chord strings or chord objects, such as
188
+ * `['G', { key: 'H', shift: true }]`.
189
189
  */
190
- export type RegisterableHotkey = RegisterableHotkeyChord | HotkeySequence;
190
+ export type RegisterableHotkeySequence = ReadonlyArray<RegisterableHotkeyChord>;
191
191
  /**
192
- * Context passed to hotkey callbacks along with the keyboard event.
192
+ * Anything that can be registered: a chord or a sequence, with each chord
193
+ * written as a string or an object.
193
194
  */
194
- export interface HotkeyCallbackContext {
195
- /** The registered hotkey: a chord string or a sequence */
196
- hotkey: Hotkey;
197
- /** The parsed chord that completed the match (the last step of a sequence) */
198
- parsedHotkey: ParsedHotkey;
195
+ export type RegisterableHotkey = RegisterableHotkeyChord | RegisterableHotkeySequence;
196
+ /** Context passed to a chord's callback. */
197
+ export interface HotkeyChordCallbackContext {
198
+ kind: 'chord';
199
+ /** The registered chord */
200
+ hotkey: HotkeyChord;
201
+ /** The chord with `Mod` resolved for the registration's platform */
202
+ parsedChord: ParsedHotkeyChord;
203
+ }
204
+ /** Context passed to a sequence's callback. */
205
+ export interface HotkeySequenceCallbackContext {
206
+ kind: 'sequence';
207
+ /** The registered sequence */
208
+ hotkey: HotkeySequence;
209
+ /** Each step with `Mod` resolved for the registration's platform */
210
+ parsedSequence: Array<ParsedHotkeyChord>;
199
211
  }
212
+ /**
213
+ * Context passed to hotkey callbacks along with the keyboard event.
214
+ * Narrow with `kind` to read `parsedChord` or `parsedSequence`.
215
+ */
216
+ export type HotkeyCallbackContext = HotkeyChordCallbackContext | HotkeySequenceCallbackContext;
217
+ /**
218
+ * The callback context for a hotkey: chord context for chords (including
219
+ * one-step tuples), sequence context for sequences, and either when the kind
220
+ * is not known statically.
221
+ */
222
+ export type HotkeyCallbackContextFor<T extends RegisterableHotkey> = [T] extends [never] ? HotkeyCallbackContext : T extends readonly [RegisterableHotkeyChord] ? HotkeyChordCallbackContext : T extends RegisterableHotkeySequence ? HotkeySequenceCallbackContext : HotkeyChordCallbackContext;
200
223
  /**
201
224
  * Callback function type for hotkey handlers.
202
225
  *
203
226
  * @param event - The keyboard event that triggered the hotkey
204
- * @param context - Additional context including the hotkey and parsed hotkey
227
+ * @param context - The registered hotkey and its parsed form. APIs that take
228
+ * one hotkey narrow it to chord or sequence context from the hotkey you pass.
205
229
  *
206
230
  * @example
207
231
  * ```ts
208
- * const handler: HotkeyCallback = (event, { hotkey, parsedHotkey }) => {
209
- * console.log(`Hotkey ${hotkey} was pressed`)
210
- * console.log(`Modifiers:`, parsedHotkey.modifiers)
232
+ * const handler: HotkeyCallback = (event, context) => {
233
+ * if (context.kind === 'chord') {
234
+ * console.log(context.hotkey, context.parsedChord.modifiers)
235
+ * } else {
236
+ * console.log(context.hotkey.join(' '), context.parsedSequence.length)
237
+ * }
211
238
  * }
212
239
  * ```
213
240
  */
214
- export type HotkeyCallback = (event: KeyboardEvent, context: HotkeyCallbackContext) => void;
241
+ export type HotkeyCallback<TContext extends HotkeyCallbackContext = HotkeyCallbackContext> = (event: KeyboardEvent, context: TContext) => void;
215
242
  /**
216
243
  * Metadata for hotkey registrations, chords and sequences alike.
217
244
  * Includes `name`, `description`, and `group` by default. Extend via declaration merging:
package/dist/index.d.ts CHANGED
@@ -1,16 +1,16 @@
1
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, FourModifierHotkey, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyChord, HotkeyMeta, HotkeySequence, ParsedHotkey, ParsedModifiers, RawHotkey, RawModifiers, RegisterableHotkey, RegisterableHotkeyChord, SingleModifierHotkey, ThreeModifierHotkey, TwoModifierHotkey } from "./hotkey.types.js";
3
- import { HotkeyChordOptions, HotkeyChordRegistration, HotkeyChordRegistrationView, HotkeyManager, HotkeyOptions, HotkeyOptionsFor, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationView, HotkeySequenceOptions, HotkeySequenceRegistration, HotkeySequenceRegistrationView, Target, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.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, HotkeyRegistrationView, HotkeyScopesState, HotkeySequenceOptions, HotkeySequenceRegistration, HotkeySequenceRegistrationView, Target, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
4
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
5
  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";
6
6
  import { KEY_DISPLAY_SYMBOLS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS } from "./display-labels.js";
7
7
  import { detectPlatform, resolveModifier } from "./platform.js";
8
8
  import { DisplayHotkey, DisplayHotkeyChord, FormatDisplayOptions, formatForDisplay, formatHotkey } from "./format.js";
9
- import { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, parseRegisterableHotkey, rawHotkeyToParsedHotkey, simplifyHotkey } from "./parse.js";
9
+ import { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey, parseHotkey, parseKeyboardEvent, simplifyHotkey } from "./parse.js";
10
10
  import { ValidatableHotkey, ValidationResult, assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
11
- import { CreateHotkeyHandlerOptions, DEFAULT_SEQUENCE_TIMEOUT, KeyboardEventMatch, MultiHotkeyHandler, areHotkeysEqual, createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher, matchesKeyboardEvent } from "./match.js";
11
+ import { CreateHotkeyChordHandlerOptions, DEFAULT_SEQUENCE_TIMEOUT, KeyboardEventMatch, MultiHotkeyChordHandler, areHotkeysEqual, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, matchesKeyboardEvent } from "./match.js";
12
12
  import { HeldModifierOptions, matchesHeldModifiers } from "./hint.js";
13
13
  import { HotkeyConflict, HotkeyConflictOptions, findHotkeyConflicts } from "./conflicts.js";
14
14
  import { KeyStateTracker, KeyStateTrackerState, getKeyStateTracker } from "./key-state-tracker.js";
15
- import { HotkeyChordRecorderOptions, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeySequenceRecorderOptions, RecorderKeyMode, RecorderOptions, RecorderRejection } from "./hotkey-recorder.js";
16
- export { ALL_KEYS, AppHotkey, AppHotkeyChordOptions, AppHotkeyDefaultKind, AppHotkeyId, AppHotkeyInput, AppHotkeyListItem, AppHotkeyOptions, AppHotkeySequenceOptions, AppHotkeyStatus, AppHotkeys, AppHotkeysState, AppHotkeysStore, AppHotkeysStoreOptions, CanonicalModifier, ConflictBehavior, CreateHotkeyHandlerOptions, CustomHotkeys, DEFAULT_SEQUENCE_TIMEOUT, DefinedAppHotkeys, DisplayHotkey, DisplayHotkeyChord, EDITING_KEYS, EditingKey, FUNCTION_KEYS, FormatDisplayOptions, FourModifierHotkey, FunctionKey, HeldModifierOptions, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyChord, HotkeyChordOptions, HotkeyChordRecorderOptions, HotkeyChordRegistration, HotkeyChordRegistrationView, HotkeyConflict, HotkeyConflictOptions, HotkeyManager, HotkeyMeta, HotkeyOptions, HotkeyOptionsFor, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationView, HotkeySequence, HotkeySequenceOptions, HotkeySequenceRecorderOptions, 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, MultiHotkeyHandler, NAVIGATION_KEYS, NUMBER_KEYS, NamedKey, NavigationKey, NonPunctuationKey, NormalizedKeyboardEvent, NumberKey, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, ParsedHotkey, ParsedModifiers, PhysicalKey, PhysicalKeyCode, PunctuationKey, RawHotkey, RawModifiers, RecorderKeyMode, RecorderOptions, RecorderRejection, Register, RegisterableHotkey, RegisterableHotkeyChord, RegisteredAppHotkeys, SingleModifierHotkey, Target, ThreeModifierHotkey, TwoModifierHotkey, ValidatableHotkey, ValidationResult, WINDOWS_MODIFIER_LABELS, areHotkeysEqual, assertValidHotkey, checkHotkey, createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher, defineAppHotkeys, detectPlatform, findHotkeyConflicts, formatForDisplay, formatHotkey, getAppHotkeyRegistrationOptions, getHotkeyManager, getKeyStateTracker, hasNonModifierKey, isAppHotkey, isCustomHotkey, isHotkeySequence, isModifierKey, isSingleLetterKey, matchesHeldModifiers, matchesKeyboardEvent, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeKeyName, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, parseRegisterableHotkey, provideAppHotkeys, publishAppHotkeysStore, rawHotkeyToParsedHotkey, resolveAppHotkey, resolveModifier, simplifyHotkey, toHotkeyRegistrationView, validateHotkey };
15
+ import { HotkeyChordRecorderOptions, HotkeyChordRecorderValidationContext, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeySequenceRecorderOptions, HotkeySequenceRecorderValidationContext, RecorderKeyMode, RecorderOptions, RecorderRejection } from "./hotkey-recorder.js";
16
+ 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, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeyRegistration, HotkeyRegistrationHandle, 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, 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,10 +1,10 @@
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, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, parseRegisterableHotkey, rawHotkeyToParsedHotkey, simplifyHotkey } from "./parse.js";
4
+ import { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey, parseHotkey, parseKeyboardEvent, simplifyHotkey } from "./parse.js";
5
5
  import { formatForDisplay, formatHotkey } from "./format.js";
6
6
  import { assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
7
- import { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual, createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher, matchesKeyboardEvent } from "./match.js";
7
+ import { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, matchesKeyboardEvent } from "./match.js";
8
8
  import { matchesHeldModifiers } from "./hint.js";
9
9
  import { HotkeyManager, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
10
10
  import { findHotkeyConflicts } from "./conflicts.js";
@@ -12,4 +12,4 @@ import { AppHotkeysStore, defineAppHotkeys, getAppHotkeyRegistrationOptions, isA
12
12
  import { KeyStateTracker, getKeyStateTracker } from "./key-state-tracker.js";
13
13
  import { HotkeyRecorder } from "./hotkey-recorder.js";
14
14
 
15
- 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, createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher, defineAppHotkeys, detectPlatform, findHotkeyConflicts, formatForDisplay, formatHotkey, getAppHotkeyRegistrationOptions, getHotkeyManager, getKeyStateTracker, hasNonModifierKey, isAppHotkey, isCustomHotkey, isHotkeySequence, isModifierKey, isSingleLetterKey, matchesHeldModifiers, matchesKeyboardEvent, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeKeyName, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, parseRegisterableHotkey, provideAppHotkeys, publishAppHotkeysStore, rawHotkeyToParsedHotkey, resolveAppHotkey, resolveModifier, simplifyHotkey, toHotkeyRegistrationView, validateHotkey };
15
+ 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, 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/match.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { HotkeyCallback, HotkeyChord, HotkeySequence, ParsedHotkey, RegisterableHotkey } from "./hotkey.types.js";
1
+ import { HotkeyCallback, HotkeyChord, HotkeyChordCallbackContext, ParsedHotkeyChord, RegisterableHotkey, RegisterableHotkeySequence } from "./hotkey.types.js";
2
2
  //#region src/match.d.ts
3
3
  export interface KeyboardEventMatch {
4
4
  matched: boolean;
@@ -24,9 +24,9 @@ export interface KeyboardEventMatch {
24
24
  * In these cases, `event.code` is used to determine the physical key.
25
25
  *
26
26
  * @param event - The KeyboardEvent to check
27
- * @param hotkey - The hotkey string or ParsedHotkey to match against
27
+ * @param chord - The chord string or parsed chord to match against
28
28
  * @param platform - The target platform for resolving 'Mod' (defaults to auto-detection)
29
- * @returns True if the event matches the hotkey
29
+ * @returns True if the event matches the chord
30
30
  *
31
31
  * @example
32
32
  * ```ts
@@ -38,29 +38,30 @@ export interface KeyboardEventMatch {
38
38
  * })
39
39
  * ```
40
40
  */
41
- export declare function matchesKeyboardEvent(event: KeyboardEvent, hotkey: HotkeyChord | ParsedHotkey, platform?: 'mac' | 'windows' | 'linux'): boolean;
41
+ export declare function matchesKeyboardEvent(event: KeyboardEvent, chord: HotkeyChord | ParsedHotkeyChord, platform?: 'mac' | 'windows' | 'linux'): boolean;
42
42
  /**
43
- * Options for creating a hotkey handler.
43
+ * Options for creating a chord handler.
44
44
  */
45
- export interface CreateHotkeyHandlerOptions {
46
- /** Prevent the default browser action when the hotkey matches. Defaults to true */
45
+ export interface CreateHotkeyChordHandlerOptions {
46
+ /** Prevent the default browser action when the chord matches. Defaults to true */
47
47
  preventDefault?: boolean;
48
- /** Stop event propagation when the hotkey matches. Defaults to true */
48
+ /** Stop event propagation when the chord matches. Defaults to true */
49
49
  stopPropagation?: boolean;
50
50
  /** The target platform for resolving 'Mod' */
51
51
  platform?: 'mac' | 'windows' | 'linux';
52
52
  }
53
53
  /**
54
- * Creates a keyboard event handler that calls the callback when the hotkey matches.
54
+ * Creates a keyboard event handler that calls the callback when the chord
55
+ * matches. For sequences, use `createSequenceMatcher`.
55
56
  *
56
- * @param hotkey - The hotkey string or ParsedHotkey to match
57
+ * @param chord - The chord string or parsed chord to match
57
58
  * @param callback - The function to call when the hotkey matches
58
59
  * @param options - Options for matching and handling
59
60
  * @returns A function that can be used as an event handler
60
61
  *
61
62
  * @example
62
63
  * ```ts
63
- * const handler = createHotkeyHandler('Mod+S', (event, { hotkey, parsedHotkey }) => {
64
+ * const handler = createHotkeyChordHandler('Mod+S', (event, { hotkey, parsedChord }) => {
64
65
  * console.log(`${hotkey} was pressed`)
65
66
  * handleSave()
66
67
  * })
@@ -68,18 +69,18 @@ export interface CreateHotkeyHandlerOptions {
68
69
  * document.addEventListener('keydown', handler)
69
70
  * ```
70
71
  */
71
- export declare function createHotkeyHandler(hotkey: HotkeyChord | ParsedHotkey, callback: HotkeyCallback, options?: CreateHotkeyHandlerOptions): (event: KeyboardEvent) => void;
72
- export type MultiHotkeyHandler = { [K in HotkeyChord]?: HotkeyCallback; };
72
+ export declare function createHotkeyChordHandler(chord: HotkeyChord | ParsedHotkeyChord, callback: HotkeyCallback<HotkeyChordCallbackContext>, options?: CreateHotkeyChordHandlerOptions): (event: KeyboardEvent) => void;
73
+ export type MultiHotkeyChordHandler = { [K in HotkeyChord]?: HotkeyCallback<HotkeyChordCallbackContext>; };
73
74
  /**
74
- * Creates a handler that matches multiple hotkeys.
75
+ * Creates a handler that matches several chords.
75
76
  *
76
- * @param handlers - A map of hotkey strings to their handlers
77
+ * @param handlers - A map of chord strings to their handlers
77
78
  * @param options - Options for matching and handling
78
79
  * @returns A function that can be used as an event handler
79
80
  *
80
81
  * @example
81
82
  * ```ts
82
- * const handler = createMultiHotkeyHandler({
83
+ * const handler = createMultiHotkeyChordHandler({
83
84
  * 'Mod+S': (event, { hotkey }) => handleSave(),
84
85
  * 'Mod+Z': (event, { hotkey }) => handleUndo(),
85
86
  * 'Mod+Shift+Z': (event, { hotkey }) => handleRedo(),
@@ -88,7 +89,7 @@ export type MultiHotkeyHandler = { [K in HotkeyChord]?: HotkeyCallback; };
88
89
  * document.addEventListener('keydown', handler)
89
90
  * ```
90
91
  */
91
- export declare function createMultiHotkeyHandler(handlers: MultiHotkeyHandler, options?: CreateHotkeyHandlerOptions): (event: KeyboardEvent) => void;
92
+ export declare function createMultiHotkeyChordHandler(handlers: MultiHotkeyChordHandler, options?: CreateHotkeyChordHandlerOptions): (event: KeyboardEvent) => void;
92
93
  /**
93
94
  * Compares normalized hotkey identity, including all four modifiers.
94
95
  * Sequences are equal when every step is equal; a one-step sequence equals its chord.
@@ -120,7 +121,7 @@ export declare const DEFAULT_SEQUENCE_TIMEOUT = 1000;
120
121
  * })
121
122
  * ```
122
123
  */
123
- export declare function createSequenceMatcher(sequence: HotkeySequence, options?: {
124
+ export declare function createSequenceMatcher(sequence: RegisterableHotkeySequence, options?: {
124
125
  timeout?: number;
125
126
  platform?: 'mac' | 'windows' | 'linux';
126
127
  }): {
package/dist/match.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { normalizeKeyName } from "./constants.js";
2
2
  import { detectPlatform } from "./platform.js";
3
3
  import { normalizeKeyboardEvent } from "./_keyboard-event.js";
4
- import { isHotkeySequence, isModifierKey, parseHotkey, parseRegisterableHotkey } from "./parse.js";
4
+ import { isHotkeySequence, isModifierKey, parseHotkey } from "./parse.js";
5
5
  import { formatHotkey } from "./format.js";
6
- import { matchKeyboardEvent, parsedHotkeysEqual } from "./_match.js";
6
+ import { matchKeyboardEvent, parsedChordsEqual } from "./_match.js";
7
7
 
8
8
  //#region src/match.ts
9
9
  /**
@@ -21,9 +21,9 @@ import { matchKeyboardEvent, parsedHotkeysEqual } from "./_match.js";
21
21
  * In these cases, `event.code` is used to determine the physical key.
22
22
  *
23
23
  * @param event - The KeyboardEvent to check
24
- * @param hotkey - The hotkey string or ParsedHotkey to match against
24
+ * @param chord - The chord string or parsed chord to match against
25
25
  * @param platform - The target platform for resolving 'Mod' (defaults to auto-detection)
26
- * @returns True if the event matches the hotkey
26
+ * @returns True if the event matches the chord
27
27
  *
28
28
  * @example
29
29
  * ```ts
@@ -35,20 +35,21 @@ import { matchKeyboardEvent, parsedHotkeysEqual } from "./_match.js";
35
35
  * })
36
36
  * ```
37
37
  */
38
- function matchesKeyboardEvent(event, hotkey, platform = detectPlatform()) {
39
- return matchKeyboardEvent(event, hotkey, platform).matched;
38
+ function matchesKeyboardEvent(event, chord, platform = detectPlatform()) {
39
+ return matchKeyboardEvent(event, chord, platform).matched;
40
40
  }
41
41
  /**
42
- * Creates a keyboard event handler that calls the callback when the hotkey matches.
42
+ * Creates a keyboard event handler that calls the callback when the chord
43
+ * matches. For sequences, use `createSequenceMatcher`.
43
44
  *
44
- * @param hotkey - The hotkey string or ParsedHotkey to match
45
+ * @param chord - The chord string or parsed chord to match
45
46
  * @param callback - The function to call when the hotkey matches
46
47
  * @param options - Options for matching and handling
47
48
  * @returns A function that can be used as an event handler
48
49
  *
49
50
  * @example
50
51
  * ```ts
51
- * const handler = createHotkeyHandler('Mod+S', (event, { hotkey, parsedHotkey }) => {
52
+ * const handler = createHotkeyChordHandler('Mod+S', (event, { hotkey, parsedChord }) => {
52
53
  * console.log(`${hotkey} was pressed`)
53
54
  * handleSave()
54
55
  * })
@@ -56,14 +57,15 @@ function matchesKeyboardEvent(event, hotkey, platform = detectPlatform()) {
56
57
  * document.addEventListener('keydown', handler)
57
58
  * ```
58
59
  */
59
- function createHotkeyHandler(hotkey, callback, options = {}) {
60
+ function createHotkeyChordHandler(chord, callback, options = {}) {
60
61
  const { preventDefault = true, stopPropagation = true, platform } = options;
61
62
  const resolvedPlatform = platform ?? detectPlatform();
62
- const hotkeyString = typeof hotkey === "string" ? hotkey : formatHotkey(hotkey);
63
- const parsed = typeof hotkey === "string" ? parseHotkey(hotkey, resolvedPlatform) : hotkey;
63
+ const hotkeyString = typeof chord === "string" ? chord : formatHotkey(chord);
64
+ const parsed = typeof chord === "string" ? parseHotkey(chord, resolvedPlatform) : chord;
64
65
  const context = {
66
+ kind: "chord",
65
67
  hotkey: hotkeyString,
66
- parsedHotkey: parsed
68
+ parsedChord: parsed
67
69
  };
68
70
  return (event) => {
69
71
  if (matchesKeyboardEvent(event, parsed, resolvedPlatform)) {
@@ -74,15 +76,15 @@ function createHotkeyHandler(hotkey, callback, options = {}) {
74
76
  };
75
77
  }
76
78
  /**
77
- * Creates a handler that matches multiple hotkeys.
79
+ * Creates a handler that matches several chords.
78
80
  *
79
- * @param handlers - A map of hotkey strings to their handlers
81
+ * @param handlers - A map of chord strings to their handlers
80
82
  * @param options - Options for matching and handling
81
83
  * @returns A function that can be used as an event handler
82
84
  *
83
85
  * @example
84
86
  * ```ts
85
- * const handler = createMultiHotkeyHandler({
87
+ * const handler = createMultiHotkeyChordHandler({
86
88
  * 'Mod+S': (event, { hotkey }) => handleSave(),
87
89
  * 'Mod+Z': (event, { hotkey }) => handleUndo(),
88
90
  * 'Mod+Shift+Z': (event, { hotkey }) => handleRedo(),
@@ -91,7 +93,7 @@ function createHotkeyHandler(hotkey, callback, options = {}) {
91
93
  * document.addEventListener('keydown', handler)
92
94
  * ```
93
95
  */
94
- function createMultiHotkeyHandler(handlers, options = {}) {
96
+ function createMultiHotkeyChordHandler(handlers, options = {}) {
95
97
  const { preventDefault = true, stopPropagation = true, platform } = options;
96
98
  const resolvedPlatform = platform ?? detectPlatform();
97
99
  const parsedHandlers = Object.entries(handlers).filter((entry) => Boolean(entry[1])).map(([hotkey, handler]) => {
@@ -100,8 +102,9 @@ function createMultiHotkeyHandler(handlers, options = {}) {
100
102
  parsed,
101
103
  handler,
102
104
  context: {
105
+ kind: "chord",
103
106
  hotkey,
104
- parsedHotkey: parsed
107
+ parsedChord: parsed
105
108
  }
106
109
  };
107
110
  });
@@ -123,7 +126,7 @@ function createMultiHotkeyHandler(handlers, options = {}) {
123
126
  function areHotkeysEqual(left, right, platform = detectPlatform()) {
124
127
  const a = isHotkeySequence(left) ? left : [left];
125
128
  const b = isHotkeySequence(right) ? right : [right];
126
- return a.length === b.length && a.every((step, index) => parsedHotkeysEqual(parseRegisterableHotkey(step, platform), parseRegisterableHotkey(b[index], platform)));
129
+ return a.length === b.length && a.every((step, index) => parsedChordsEqual(parseHotkey(step, platform), parseHotkey(b[index], platform)));
127
130
  }
128
131
  /** Default timeout between sequence steps (in milliseconds). */
129
132
  const DEFAULT_SEQUENCE_TIMEOUT = 1e3;
@@ -152,7 +155,7 @@ const DEFAULT_SEQUENCE_TIMEOUT = 1e3;
152
155
  function createSequenceMatcher(sequence, options = {}) {
153
156
  const platform = options.platform ?? detectPlatform();
154
157
  const timeout = options.timeout ?? 1e3;
155
- const parsedSequence = sequence.map((hotkey) => parseHotkey(hotkey, platform));
158
+ const parsedSequence = parseHotkey(sequence, platform);
156
159
  let currentIndex = 0;
157
160
  let lastKeyTime = 0;
158
161
  return {
@@ -188,4 +191,4 @@ function createSequenceMatcher(sequence, options = {}) {
188
191
  }
189
192
 
190
193
  //#endregion
191
- export { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual, createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher, matchesKeyboardEvent };
194
+ export { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, matchesKeyboardEvent };