use-kbd 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -36
- package/dist/index.cjs +1374 -285
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +405 -56
- package/dist/index.d.ts +405 -56
- package/dist/index.js +1339 -281
- package/dist/index.js.map +1 -1
- package/package.json +6 -8
- package/src/styles.css +255 -65
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
|
-
import { ReactNode, RefObject,
|
|
3
|
+
import { ReactNode, ComponentType, RefObject, SVGProps, CSSProperties } from 'react';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Modifier keys state
|
|
7
|
+
*/
|
|
8
|
+
interface Modifiers {
|
|
9
|
+
ctrl: boolean;
|
|
10
|
+
alt: boolean;
|
|
11
|
+
shift: boolean;
|
|
12
|
+
meta: boolean;
|
|
13
|
+
}
|
|
5
14
|
/**
|
|
6
15
|
* Represents a single key press (possibly with modifiers)
|
|
7
16
|
*/
|
|
@@ -9,19 +18,73 @@ interface KeyCombination {
|
|
|
9
18
|
/** The main key (lowercase, e.g., 'k', 'enter', 'arrowup') */
|
|
10
19
|
key: string;
|
|
11
20
|
/** Modifier keys pressed */
|
|
12
|
-
modifiers:
|
|
13
|
-
ctrl: boolean;
|
|
14
|
-
alt: boolean;
|
|
15
|
-
shift: boolean;
|
|
16
|
-
meta: boolean;
|
|
17
|
-
};
|
|
21
|
+
modifiers: Modifiers;
|
|
18
22
|
}
|
|
19
23
|
/**
|
|
20
24
|
* Represents a hotkey - either a single key or a sequence of keys.
|
|
21
25
|
* Single key: [{ key: 'k', modifiers: {...} }]
|
|
22
26
|
* Sequence: [{ key: '2', ... }, { key: 'w', ... }]
|
|
27
|
+
* @deprecated Use KeySeq for new code
|
|
23
28
|
*/
|
|
24
29
|
type HotkeySequence = KeyCombination[];
|
|
30
|
+
/**
|
|
31
|
+
* A single element in a key sequence (sum type).
|
|
32
|
+
* - 'key': exact key match (with optional modifiers)
|
|
33
|
+
* - 'digit': matches any single digit 0-9 (\d)
|
|
34
|
+
* - 'digits': matches one or more digits (\d+)
|
|
35
|
+
*/
|
|
36
|
+
type SeqElem = {
|
|
37
|
+
type: 'key';
|
|
38
|
+
key: string;
|
|
39
|
+
modifiers: Modifiers;
|
|
40
|
+
} | {
|
|
41
|
+
type: 'digit';
|
|
42
|
+
} | {
|
|
43
|
+
type: 'digits';
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* A key sequence pattern (array of sequence elements)
|
|
47
|
+
*/
|
|
48
|
+
type KeySeq = SeqElem[];
|
|
49
|
+
/**
|
|
50
|
+
* Sequence element with match state (for tracking during input).
|
|
51
|
+
* - 'key': has `matched` flag
|
|
52
|
+
* - 'digit': has captured `value`
|
|
53
|
+
* - 'digits': has captured `value` or in-progress `partial` string
|
|
54
|
+
*/
|
|
55
|
+
type SeqElemState = {
|
|
56
|
+
type: 'key';
|
|
57
|
+
key: string;
|
|
58
|
+
modifiers: Modifiers;
|
|
59
|
+
matched?: true;
|
|
60
|
+
} | {
|
|
61
|
+
type: 'digit';
|
|
62
|
+
value?: number;
|
|
63
|
+
} | {
|
|
64
|
+
type: 'digits';
|
|
65
|
+
value?: number;
|
|
66
|
+
partial?: string;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Sequence match state - tracks progress through a sequence with captures
|
|
70
|
+
*/
|
|
71
|
+
type SeqMatchState = SeqElemState[];
|
|
72
|
+
/**
|
|
73
|
+
* Extract captured values from a completed sequence match
|
|
74
|
+
*/
|
|
75
|
+
declare function extractCaptures(state: SeqMatchState): number[];
|
|
76
|
+
/**
|
|
77
|
+
* Check if a SeqElem is a digit placeholder
|
|
78
|
+
*/
|
|
79
|
+
declare function isDigitPlaceholder(elem: SeqElem): elem is {
|
|
80
|
+
type: 'digit';
|
|
81
|
+
} | {
|
|
82
|
+
type: 'digits';
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Count digit placeholders in a sequence
|
|
86
|
+
*/
|
|
87
|
+
declare function countPlaceholders(seq: KeySeq): number;
|
|
25
88
|
/**
|
|
26
89
|
* Platform-aware display format for a key combination or sequence
|
|
27
90
|
*/
|
|
@@ -53,6 +116,8 @@ interface RecordHotkeyResult {
|
|
|
53
116
|
pendingKeys: HotkeySequence;
|
|
54
117
|
/** The key currently being held (for live UI feedback during recording) */
|
|
55
118
|
activeKeys: KeyCombination | null;
|
|
119
|
+
/** The timeout duration for sequences (ms) */
|
|
120
|
+
sequenceTimeout: number;
|
|
56
121
|
/**
|
|
57
122
|
* @deprecated Use `sequence` instead
|
|
58
123
|
*/
|
|
@@ -72,7 +137,9 @@ interface RecordHotkeyOptions {
|
|
|
72
137
|
onShiftTab?: () => void;
|
|
73
138
|
/** Prevent default on captured keys (default: true) */
|
|
74
139
|
preventDefault?: boolean;
|
|
75
|
-
/** Timeout in ms before sequence is submitted (default:
|
|
140
|
+
/** Timeout in ms before sequence is submitted (default: Infinity, no timeout).
|
|
141
|
+
* Set to 0 for immediate submit (no sequences - first key press is captured).
|
|
142
|
+
* Set to a finite number for auto-submit after that duration. */
|
|
76
143
|
sequenceTimeout?: number;
|
|
77
144
|
/** When true, pause the auto-submit timeout (useful for conflict warnings). Default: false */
|
|
78
145
|
pauseTimeout?: boolean;
|
|
@@ -131,10 +198,14 @@ interface SequenceCompletion {
|
|
|
131
198
|
* Hotkey definition - maps key combinations/sequences to action names
|
|
132
199
|
*/
|
|
133
200
|
type HotkeyMap = Record<string, string | string[]>;
|
|
201
|
+
/**
|
|
202
|
+
* Handler function type - can optionally receive captured values
|
|
203
|
+
*/
|
|
204
|
+
type HotkeyHandler = (e: KeyboardEvent, captures?: number[]) => void;
|
|
134
205
|
/**
|
|
135
206
|
* Handler map - maps action names to handler functions
|
|
136
207
|
*/
|
|
137
|
-
type HandlerMap = Record<string,
|
|
208
|
+
type HandlerMap = Record<string, HotkeyHandler>;
|
|
138
209
|
interface UseHotkeysOptions {
|
|
139
210
|
/** Whether hotkeys are enabled (default: true) */
|
|
140
211
|
enabled?: boolean;
|
|
@@ -146,7 +217,7 @@ interface UseHotkeysOptions {
|
|
|
146
217
|
stopPropagation?: boolean;
|
|
147
218
|
/** Enable hotkeys even when focused on input/textarea/select (default: false) */
|
|
148
219
|
enableOnFormTags?: boolean;
|
|
149
|
-
/** Timeout in ms for sequences (default:
|
|
220
|
+
/** Timeout in ms for sequences (default: Infinity, no timeout) */
|
|
150
221
|
sequenceTimeout?: number;
|
|
151
222
|
/** What happens on timeout: 'submit' executes current sequence, 'cancel' resets (default: 'submit') */
|
|
152
223
|
onTimeout?: 'submit' | 'cancel';
|
|
@@ -183,8 +254,7 @@ interface UseHotkeysResult {
|
|
|
183
254
|
* // Sequences
|
|
184
255
|
* const { pendingKeys, isAwaitingSequence } = useHotkeys(
|
|
185
256
|
* { '2 w': 'twoWeeks', '2 d': 'twoDays' },
|
|
186
|
-
* { twoWeeks: () => setRange('2w'), twoDays: () => setRange('2d') }
|
|
187
|
-
* { sequenceTimeout: 1000 }
|
|
257
|
+
* { twoWeeks: () => setRange('2w'), twoDays: () => setRange('2d') }
|
|
188
258
|
* )
|
|
189
259
|
* ```
|
|
190
260
|
*/
|
|
@@ -399,6 +469,19 @@ interface BindingInfo {
|
|
|
399
469
|
*/
|
|
400
470
|
declare function KeybindingEditor({ keymap, defaults, descriptions, onChange, onReset, className, children, }: KeybindingEditorProps): react_jsx_runtime.JSX.Element;
|
|
401
471
|
|
|
472
|
+
/**
|
|
473
|
+
* Props for a tooltip wrapper component.
|
|
474
|
+
* Compatible with MUI Tooltip and similar libraries.
|
|
475
|
+
*/
|
|
476
|
+
interface TooltipProps {
|
|
477
|
+
title: string;
|
|
478
|
+
children: ReactNode;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* A component that wraps children with a tooltip.
|
|
482
|
+
* Default uses native title attribute; can be replaced with MUI Tooltip etc.
|
|
483
|
+
*/
|
|
484
|
+
type TooltipComponent = ComponentType<TooltipProps>;
|
|
402
485
|
interface ShortcutGroup {
|
|
403
486
|
name: string;
|
|
404
487
|
shortcuts: Array<{
|
|
@@ -474,13 +557,12 @@ interface ShortcutsModalProps {
|
|
|
474
557
|
* If not provided, uses closeModal from HotkeysContext.
|
|
475
558
|
*/
|
|
476
559
|
onClose?: () => void;
|
|
477
|
-
/** Hotkey to open modal (default: '?'). Set to empty string to disable. */
|
|
478
|
-
openKey?: string;
|
|
479
560
|
/**
|
|
480
|
-
*
|
|
481
|
-
*
|
|
561
|
+
* Default keybinding to open shortcuts modal (default: '?').
|
|
562
|
+
* Users can override this in the shortcuts modal.
|
|
563
|
+
* Set to empty string to disable.
|
|
482
564
|
*/
|
|
483
|
-
|
|
565
|
+
defaultBinding?: string;
|
|
484
566
|
/** Enable editing mode */
|
|
485
567
|
editable?: boolean;
|
|
486
568
|
/** Called when a binding changes (required if editable) */
|
|
@@ -503,6 +585,14 @@ interface ShortcutsModalProps {
|
|
|
503
585
|
title?: string;
|
|
504
586
|
/** Hint text shown below title (e.g., "Click any key to customize") */
|
|
505
587
|
hint?: string;
|
|
588
|
+
/** Whether to show actions with no bindings (default: true in editable mode, false otherwise) */
|
|
589
|
+
showUnbound?: boolean;
|
|
590
|
+
/**
|
|
591
|
+
* Custom tooltip component for digit placeholders.
|
|
592
|
+
* Should accept { title: string, children: ReactNode } props.
|
|
593
|
+
* Default uses native title attribute. Can be MUI Tooltip, etc.
|
|
594
|
+
*/
|
|
595
|
+
TooltipComponent?: TooltipComponent;
|
|
506
596
|
}
|
|
507
597
|
interface ShortcutsModalRenderProps {
|
|
508
598
|
groups: ShortcutGroup[];
|
|
@@ -519,20 +609,31 @@ interface ShortcutsModalRenderProps {
|
|
|
519
609
|
reset: () => void;
|
|
520
610
|
}
|
|
521
611
|
/**
|
|
522
|
-
* Modal
|
|
612
|
+
* Modal for displaying all keyboard shortcuts, organized by group.
|
|
613
|
+
*
|
|
614
|
+
* Opens by default with `?` key. Shows all registered actions and their bindings,
|
|
615
|
+
* grouped by category (e.g., "Navigation", "Edit", "Global").
|
|
616
|
+
*
|
|
617
|
+
* Features:
|
|
618
|
+
* - **Editable bindings**: Click any shortcut to rebind it (when `editable` is true)
|
|
619
|
+
* - **Conflict detection**: Warns when a binding conflicts with existing shortcuts
|
|
620
|
+
* - **Custom group renderers**: Use `groupRenderers` for custom layouts (e.g., two-column for fwd/back pairs)
|
|
621
|
+
* - **Persistence**: Integrates with HotkeysProvider's localStorage persistence
|
|
523
622
|
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
623
|
+
* Unlike Omnibar (search-first) or LookupModal (type keys to filter), ShortcutsModal
|
|
624
|
+
* shows everything at once in a browsable, organized view.
|
|
625
|
+
*
|
|
626
|
+
* Styled via CSS custom properties: --kbd-bg, --kbd-text, --kbd-kbd-bg, etc.
|
|
526
627
|
*
|
|
527
628
|
* @example
|
|
528
629
|
* ```tsx
|
|
529
|
-
* //
|
|
530
|
-
* <
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
*
|
|
630
|
+
* // Basic usage with HotkeysProvider (recommended)
|
|
631
|
+
* <HotkeysProvider>
|
|
632
|
+
* <App />
|
|
633
|
+
* <ShortcutsModal editable />
|
|
634
|
+
* </HotkeysProvider>
|
|
534
635
|
*
|
|
535
|
-
* //
|
|
636
|
+
* // Standalone with explicit props
|
|
536
637
|
* <ShortcutsModal
|
|
537
638
|
* keymap={keymap}
|
|
538
639
|
* defaults={DEFAULT_KEYMAP}
|
|
@@ -543,7 +644,7 @@ interface ShortcutsModalRenderProps {
|
|
|
543
644
|
* />
|
|
544
645
|
* ```
|
|
545
646
|
*/
|
|
546
|
-
declare function ShortcutsModal({ keymap: keymapProp, defaults: defaultsProp, labels: labelsProp, descriptions: descriptionsProp, groups: groupNamesProp, groupOrder, groupRenderers, isOpen: isOpenProp, onClose: onCloseProp,
|
|
647
|
+
declare function ShortcutsModal({ keymap: keymapProp, defaults: defaultsProp, labels: labelsProp, descriptions: descriptionsProp, groups: groupNamesProp, groupOrder, groupRenderers, isOpen: isOpenProp, onClose: onCloseProp, defaultBinding, editable, onBindingChange, onBindingAdd, onBindingRemove, onReset, multipleBindings, children, backdropClassName, modalClassName, title, hint, showUnbound, TooltipComponent: TooltipComponentProp, }: ShortcutsModalProps): react_jsx_runtime.JSX.Element | null;
|
|
547
648
|
|
|
548
649
|
/**
|
|
549
650
|
* Configuration for a row in a two-column table
|
|
@@ -613,13 +714,12 @@ interface OmnibarProps {
|
|
|
613
714
|
* If not provided, uses keymap from HotkeysContext.
|
|
614
715
|
*/
|
|
615
716
|
keymap?: HotkeyMap;
|
|
616
|
-
/** Hotkey to open omnibar (default: 'meta+k'). Set to empty string to disable. */
|
|
617
|
-
openKey?: string;
|
|
618
717
|
/**
|
|
619
|
-
*
|
|
620
|
-
*
|
|
718
|
+
* Default keybinding to open omnibar (default: 'meta+k').
|
|
719
|
+
* Users can override this in the shortcuts modal.
|
|
720
|
+
* Set to empty string to disable.
|
|
621
721
|
*/
|
|
622
|
-
|
|
722
|
+
defaultBinding?: string;
|
|
623
723
|
/**
|
|
624
724
|
* Control visibility externally.
|
|
625
725
|
* If not provided, uses isOmnibarOpen from HotkeysContext.
|
|
@@ -663,13 +763,31 @@ interface OmnibarRenderProps {
|
|
|
663
763
|
inputRef: RefObject<HTMLInputElement | null>;
|
|
664
764
|
}
|
|
665
765
|
/**
|
|
666
|
-
*
|
|
766
|
+
* Command palette for searching and executing actions by name.
|
|
767
|
+
*
|
|
768
|
+
* Opens by default with `⌘K` (macOS) or `Ctrl+K` (Windows/Linux). Type to search
|
|
769
|
+
* across all registered actions by label, then press Enter to execute.
|
|
770
|
+
*
|
|
771
|
+
* Features:
|
|
772
|
+
* - **Fuzzy search**: Matches action labels (e.g., "nav tab" finds "Navigate to Table")
|
|
773
|
+
* - **Keyboard navigation**: Arrow keys to select, Enter to execute, Escape to close
|
|
774
|
+
* - **Binding display**: Shows keyboard shortcuts next to each result
|
|
775
|
+
* - **Sequence support**: Can also match and execute key sequences
|
|
776
|
+
*
|
|
777
|
+
* Unlike ShortcutsModal (shows all shortcuts organized by group) or LookupModal
|
|
778
|
+
* (type keys to filter by binding), Omnibar is search-first by action name/label.
|
|
667
779
|
*
|
|
668
|
-
*
|
|
669
|
-
* --kbd-bg, --kbd-text, --kbd-accent, etc.
|
|
780
|
+
* Styled via CSS custom properties: --kbd-bg, --kbd-text, --kbd-accent, etc.
|
|
670
781
|
*
|
|
671
782
|
* @example
|
|
672
783
|
* ```tsx
|
|
784
|
+
* // Basic usage with HotkeysProvider (recommended)
|
|
785
|
+
* <HotkeysProvider>
|
|
786
|
+
* <App />
|
|
787
|
+
* <Omnibar />
|
|
788
|
+
* </HotkeysProvider>
|
|
789
|
+
*
|
|
790
|
+
* // Standalone with explicit props
|
|
673
791
|
* <Omnibar
|
|
674
792
|
* actions={ACTIONS}
|
|
675
793
|
* handlers={HANDLERS}
|
|
@@ -678,8 +796,13 @@ interface OmnibarRenderProps {
|
|
|
678
796
|
* />
|
|
679
797
|
* ```
|
|
680
798
|
*/
|
|
681
|
-
declare function Omnibar({ actions: actionsProp, handlers: handlersProp, keymap: keymapProp,
|
|
799
|
+
declare function Omnibar({ actions: actionsProp, handlers: handlersProp, keymap: keymapProp, defaultBinding, isOpen: isOpenProp, onOpen: onOpenProp, onClose: onCloseProp, onExecute: onExecuteProp, maxResults, placeholder, children, backdropClassName, omnibarClassName, }: OmnibarProps): react_jsx_runtime.JSX.Element | null;
|
|
682
800
|
|
|
801
|
+
/**
|
|
802
|
+
* Check if a key is a shifted symbol (requires Shift on US keyboard).
|
|
803
|
+
* For these keys, shift modifier should be implicit, not shown separately.
|
|
804
|
+
*/
|
|
805
|
+
declare function isShiftedSymbol(key: string): boolean;
|
|
683
806
|
/**
|
|
684
807
|
* Detect if running on macOS
|
|
685
808
|
*/
|
|
@@ -692,11 +815,32 @@ declare function normalizeKey(key: string): string;
|
|
|
692
815
|
* Format a key for display (platform-aware)
|
|
693
816
|
*/
|
|
694
817
|
declare function formatKeyForDisplay(key: string): string;
|
|
818
|
+
/**
|
|
819
|
+
* Sentinel values for digit placeholders in KeyCombination.key
|
|
820
|
+
* These are used during recording to represent placeholder patterns.
|
|
821
|
+
*/
|
|
822
|
+
declare const DIGIT_PLACEHOLDER = "__DIGIT__";
|
|
823
|
+
declare const DIGITS_PLACEHOLDER = "__DIGITS__";
|
|
824
|
+
/**
|
|
825
|
+
* Check if a key string is a digit placeholder sentinel value.
|
|
826
|
+
* Used during recording to identify placeholder keys.
|
|
827
|
+
*/
|
|
828
|
+
declare function isPlaceholderSentinel(key: string): boolean;
|
|
695
829
|
/**
|
|
696
830
|
* Convert a KeyCombination or HotkeySequence to display format
|
|
697
831
|
*/
|
|
698
832
|
declare function formatCombination(combo: KeyCombination): KeyCombinationDisplay;
|
|
699
833
|
declare function formatCombination(sequence: HotkeySequence): KeyCombinationDisplay;
|
|
834
|
+
/**
|
|
835
|
+
* Format a binding string for display.
|
|
836
|
+
* Takes a binding like "meta+k" or "2 w" and returns a display string like "⌘K" or "2 W".
|
|
837
|
+
*
|
|
838
|
+
* @example
|
|
839
|
+
* formatBinding('meta+k') // "⌘K" on Mac, "Ctrl+K" on Windows
|
|
840
|
+
* formatBinding('2 w') // "2 W"
|
|
841
|
+
* formatBinding('?') // "?"
|
|
842
|
+
*/
|
|
843
|
+
declare function formatBinding(binding: string): string;
|
|
700
844
|
/**
|
|
701
845
|
* Check if a key is a modifier key
|
|
702
846
|
*/
|
|
@@ -715,6 +859,34 @@ declare function parseHotkeyString(hotkeyStr: string): HotkeySequence;
|
|
|
715
859
|
* @deprecated Use parseHotkeyString for sequence support
|
|
716
860
|
*/
|
|
717
861
|
declare function parseCombinationId(id: string): KeyCombination;
|
|
862
|
+
/**
|
|
863
|
+
* Parse a hotkey string to a KeySeq (new sequence type with digit placeholders).
|
|
864
|
+
* Handles both single keys ("ctrl+k") and sequences ("2 w", "\\d+ d")
|
|
865
|
+
*
|
|
866
|
+
* @example
|
|
867
|
+
* parseKeySeq('\\d+ d') // [{ type: 'digits' }, { type: 'key', key: 'd', ... }]
|
|
868
|
+
* parseKeySeq('ctrl+k') // [{ type: 'key', key: 'k', modifiers: { ctrl: true, ... } }]
|
|
869
|
+
*/
|
|
870
|
+
declare function parseKeySeq(hotkeyStr: string): KeySeq;
|
|
871
|
+
/**
|
|
872
|
+
* Format a KeySeq to display format
|
|
873
|
+
*/
|
|
874
|
+
declare function formatKeySeq(seq: KeySeq): KeyCombinationDisplay;
|
|
875
|
+
/**
|
|
876
|
+
* Check if a KeySeq contains any digit placeholders
|
|
877
|
+
*/
|
|
878
|
+
declare function hasDigitPlaceholders(seq: KeySeq): boolean;
|
|
879
|
+
/**
|
|
880
|
+
* Convert a KeySeq to HotkeySequence (for backwards compatibility).
|
|
881
|
+
* Note: Digit placeholders become literal '\d' or '\d+' keys.
|
|
882
|
+
* This is only useful for legacy code paths.
|
|
883
|
+
*/
|
|
884
|
+
declare function keySeqToHotkeySequence(seq: KeySeq): HotkeySequence;
|
|
885
|
+
/**
|
|
886
|
+
* Convert a HotkeySequence to KeySeq (for migration).
|
|
887
|
+
* Note: This does NOT detect digit patterns - use parseKeySeq for that.
|
|
888
|
+
*/
|
|
889
|
+
declare function hotkeySequenceToKeySeq(seq: HotkeySequence): KeySeq;
|
|
718
890
|
/**
|
|
719
891
|
* Conflict detection result
|
|
720
892
|
*/
|
|
@@ -730,6 +902,7 @@ interface KeyConflict {
|
|
|
730
902
|
* Find conflicts in a keymap.
|
|
731
903
|
* Detects:
|
|
732
904
|
* - Duplicate: multiple actions bound to the exact same key/sequence
|
|
905
|
+
* - Pattern overlap: digit patterns that could match the same input (e.g., "\d d" and "5 d")
|
|
733
906
|
* - Prefix: one hotkey is a prefix of another (e.g., "2" and "2 w")
|
|
734
907
|
*
|
|
735
908
|
* @param keymap - HotkeyMap to check for conflicts
|
|
@@ -797,6 +970,23 @@ declare function fuzzyMatch(pattern: string, text: string): FuzzyMatchResult;
|
|
|
797
970
|
*/
|
|
798
971
|
declare function searchActions(query: string, actions: ActionRegistry, keymap?: Record<string, string | string[]>): ActionSearchResult[];
|
|
799
972
|
|
|
973
|
+
/**
|
|
974
|
+
* Handler function for actions.
|
|
975
|
+
* Optionally receives captured values from digit placeholders in bindings.
|
|
976
|
+
*
|
|
977
|
+
* @example
|
|
978
|
+
* ```tsx
|
|
979
|
+
* // Simple handler (no captures)
|
|
980
|
+
* handler: () => setPage(1)
|
|
981
|
+
*
|
|
982
|
+
* // Handler with captures (e.g., for binding "\d+ j")
|
|
983
|
+
* handler: (e, captures) => {
|
|
984
|
+
* const n = captures?.[0] ?? 1
|
|
985
|
+
* setRow(row + n)
|
|
986
|
+
* }
|
|
987
|
+
* ```
|
|
988
|
+
*/
|
|
989
|
+
type ActionHandler = (e?: KeyboardEvent, captures?: number[]) => void;
|
|
800
990
|
interface ActionConfig {
|
|
801
991
|
/** Human-readable label for omnibar/modal */
|
|
802
992
|
label: string;
|
|
@@ -806,8 +996,8 @@ interface ActionConfig {
|
|
|
806
996
|
defaultBindings?: string[];
|
|
807
997
|
/** Search keywords for omnibar */
|
|
808
998
|
keywords?: string[];
|
|
809
|
-
/** The action handler */
|
|
810
|
-
handler:
|
|
999
|
+
/** The action handler (optionally receives KeyboardEvent and captured values) */
|
|
1000
|
+
handler: ActionHandler;
|
|
811
1001
|
/** Whether action is currently enabled (default: true) */
|
|
812
1002
|
enabled?: boolean;
|
|
813
1003
|
/** Priority for conflict resolution (higher wins, default: 0) */
|
|
@@ -874,12 +1064,14 @@ interface ActionsRegistryValue {
|
|
|
874
1064
|
actionRegistry: ActionRegistry;
|
|
875
1065
|
/** Get all bindings for an action (defaults + overrides) */
|
|
876
1066
|
getBindingsForAction: (id: string) => string[];
|
|
1067
|
+
/** Get the first binding for an action (convenience for display) */
|
|
1068
|
+
getFirstBindingForAction: (id: string) => string | undefined;
|
|
877
1069
|
/** User's binding overrides */
|
|
878
1070
|
overrides: Record<string, string | string[]>;
|
|
879
1071
|
/** Set a user override for a binding */
|
|
880
1072
|
setBinding: (actionId: string, key: string) => void;
|
|
881
|
-
/** Remove a binding */
|
|
882
|
-
removeBinding: (key: string) => void;
|
|
1073
|
+
/** Remove a binding for a specific action */
|
|
1074
|
+
removeBinding: (actionId: string, key: string) => void;
|
|
883
1075
|
/** Reset all overrides */
|
|
884
1076
|
resetOverrides: () => void;
|
|
885
1077
|
}
|
|
@@ -900,7 +1092,7 @@ declare function useActionsRegistry(options?: UseActionsRegistryOptions): Action
|
|
|
900
1092
|
interface HotkeysConfig {
|
|
901
1093
|
/** Storage key for persisting user binding overrides */
|
|
902
1094
|
storageKey?: string;
|
|
903
|
-
/** Timeout in ms before a sequence auto-submits (default:
|
|
1095
|
+
/** Timeout in ms before a sequence auto-submits (default: Infinity, no timeout) */
|
|
904
1096
|
sequenceTimeout?: number;
|
|
905
1097
|
/** When true, keys with conflicts are disabled (default: true) */
|
|
906
1098
|
disableConflicts?: boolean;
|
|
@@ -908,10 +1100,6 @@ interface HotkeysConfig {
|
|
|
908
1100
|
minViewportWidth?: number | false;
|
|
909
1101
|
/** Whether to show hotkey UI on touch-only devices (default: false) */
|
|
910
1102
|
enableOnTouch?: boolean;
|
|
911
|
-
/** Key sequence to open shortcuts modal (false to disable) */
|
|
912
|
-
modalTrigger?: string | false;
|
|
913
|
-
/** Key sequence to open omnibar (false to disable) */
|
|
914
|
-
omnibarTrigger?: string | false;
|
|
915
1103
|
}
|
|
916
1104
|
/**
|
|
917
1105
|
* Context value for hotkeys.
|
|
@@ -937,6 +1125,18 @@ interface HotkeysContextValue {
|
|
|
937
1125
|
closeOmnibar: () => void;
|
|
938
1126
|
/** Toggle the omnibar */
|
|
939
1127
|
toggleOmnibar: () => void;
|
|
1128
|
+
/** Whether currently editing a binding in ShortcutsModal */
|
|
1129
|
+
isEditingBinding: boolean;
|
|
1130
|
+
/** Set editing state (called by ShortcutsModal) */
|
|
1131
|
+
setIsEditingBinding: (value: boolean) => void;
|
|
1132
|
+
/** Lookup modal open state */
|
|
1133
|
+
isLookupOpen: boolean;
|
|
1134
|
+
/** Open the lookup modal */
|
|
1135
|
+
openLookup: () => void;
|
|
1136
|
+
/** Close the lookup modal */
|
|
1137
|
+
closeLookup: () => void;
|
|
1138
|
+
/** Toggle the lookup modal */
|
|
1139
|
+
toggleLookup: () => void;
|
|
940
1140
|
/** Execute an action by ID */
|
|
941
1141
|
executeAction: (id: string) => void;
|
|
942
1142
|
/** Sequence state: pending key combinations */
|
|
@@ -955,6 +1155,8 @@ interface HotkeysContextValue {
|
|
|
955
1155
|
searchActions: (query: string) => ReturnType<typeof searchActions>;
|
|
956
1156
|
/** Get sequence completions for pending keys */
|
|
957
1157
|
getCompletions: (pendingKeys: HotkeySequence) => ReturnType<typeof getSequenceCompletions>;
|
|
1158
|
+
/** Cancel the current sequence */
|
|
1159
|
+
cancelSequence: () => void;
|
|
958
1160
|
}
|
|
959
1161
|
interface HotkeysProviderProps {
|
|
960
1162
|
config?: HotkeysConfig;
|
|
@@ -1020,7 +1222,7 @@ declare function useMaybeHotkeysContext(): HotkeysContextValue | null;
|
|
|
1020
1222
|
* console.log('Captured:', display.display) // "2 W" or "⌘K"
|
|
1021
1223
|
* saveKeybinding(display.id) // "2 w" or "meta+k"
|
|
1022
1224
|
* },
|
|
1023
|
-
* sequenceTimeout:
|
|
1225
|
+
* sequenceTimeout: 800, // custom timeout
|
|
1024
1226
|
* })
|
|
1025
1227
|
*
|
|
1026
1228
|
* return (
|
|
@@ -1037,28 +1239,175 @@ declare function useMaybeHotkeysContext(): HotkeysContextValue | null;
|
|
|
1037
1239
|
*/
|
|
1038
1240
|
declare function useRecordHotkey(options?: RecordHotkeyOptions): RecordHotkeyResult;
|
|
1039
1241
|
|
|
1242
|
+
interface KbdProps {
|
|
1243
|
+
/** Action ID to display binding(s) for */
|
|
1244
|
+
action: string;
|
|
1245
|
+
/** Separator between multiple bindings (default: " / ") */
|
|
1246
|
+
separator?: string;
|
|
1247
|
+
/** Show all bindings instead of just the first (default: false, shows only first) */
|
|
1248
|
+
all?: boolean;
|
|
1249
|
+
/** Fallback content when no bindings exist */
|
|
1250
|
+
fallback?: React.ReactNode;
|
|
1251
|
+
/** Additional className */
|
|
1252
|
+
className?: string;
|
|
1253
|
+
/** Make the kbd clickable to trigger the action */
|
|
1254
|
+
clickable?: boolean;
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Display the current binding(s) for an action (clickable by default).
|
|
1258
|
+
*
|
|
1259
|
+
* Automatically updates when users customize their bindings.
|
|
1260
|
+
* Uses SVG icons for modifiers (⌘, ⌥, ⇧, ⌃) and special keys (arrows, enter, etc.)
|
|
1261
|
+
*
|
|
1262
|
+
* @example
|
|
1263
|
+
* ```tsx
|
|
1264
|
+
* // Clickable kbd that triggers the action (default)
|
|
1265
|
+
* <p>Press <Kbd action="help" /> to see shortcuts</p>
|
|
1266
|
+
*
|
|
1267
|
+
* // Non-clickable for pure display (use Key alias or clickable={false})
|
|
1268
|
+
* <p>Navigate with <Key action="next" /> to go to next item</p>
|
|
1269
|
+
*
|
|
1270
|
+
* // Show all bindings (not just the first)
|
|
1271
|
+
* <p>Navigate with <Kbd action="next" all separator=" or " /></p>
|
|
1272
|
+
*
|
|
1273
|
+
* // With fallback when no binding exists
|
|
1274
|
+
* <Kbd action="customAction" fallback="(unbound)" />
|
|
1275
|
+
* ```
|
|
1276
|
+
*/
|
|
1277
|
+
declare function Kbd({ action, separator, all, fallback, className, clickable, }: KbdProps): react_jsx_runtime.JSX.Element | null;
|
|
1278
|
+
/**
|
|
1279
|
+
* Non-clickable variant of Kbd for pure display/documentation purposes.
|
|
1280
|
+
* Alias for `<Kbd clickable={false} ... />`
|
|
1281
|
+
*/
|
|
1282
|
+
declare function Key(props: Omit<KbdProps, 'clickable'>): react_jsx_runtime.JSX.Element;
|
|
1283
|
+
/**
|
|
1284
|
+
* Display all bindings for an action (shows multiple if they exist).
|
|
1285
|
+
* Alias for `<Kbd all ... />`
|
|
1286
|
+
*
|
|
1287
|
+
* @example
|
|
1288
|
+
* ```tsx
|
|
1289
|
+
* <p>Navigate with <Kbds action="next" separator=" or " /></p>
|
|
1290
|
+
* ```
|
|
1291
|
+
*/
|
|
1292
|
+
declare function Kbds(props: Omit<KbdProps, 'all'>): react_jsx_runtime.JSX.Element;
|
|
1293
|
+
type BuiltinKbdProps = Omit<KbdProps, 'action'>;
|
|
1294
|
+
/**
|
|
1295
|
+
* Kbd for the ShortcutsModal trigger (default: `?`).
|
|
1296
|
+
* @example <KbdModal /> // Shows "?" or user's custom binding
|
|
1297
|
+
*/
|
|
1298
|
+
declare function KbdModal(props: BuiltinKbdProps): react_jsx_runtime.JSX.Element;
|
|
1299
|
+
/**
|
|
1300
|
+
* Kbd for the Omnibar trigger (default: `⌘K`).
|
|
1301
|
+
* @example <KbdOmnibar /> // Shows "⌘K" or user's custom binding
|
|
1302
|
+
*/
|
|
1303
|
+
declare function KbdOmnibar(props: BuiltinKbdProps): react_jsx_runtime.JSX.Element;
|
|
1304
|
+
/**
|
|
1305
|
+
* Kbd for the LookupModal trigger (default: `⌘⇧K`).
|
|
1306
|
+
* @example <KbdLookup /> // Shows "⌘⇧K" or user's custom binding
|
|
1307
|
+
*/
|
|
1308
|
+
declare function KbdLookup(props: BuiltinKbdProps): react_jsx_runtime.JSX.Element;
|
|
1309
|
+
|
|
1310
|
+
interface LookupModalProps {
|
|
1311
|
+
/**
|
|
1312
|
+
* Default keybinding to open lookup modal (default: 'meta+shift+k').
|
|
1313
|
+
* Users can override this in the shortcuts modal.
|
|
1314
|
+
* Set to empty string to disable.
|
|
1315
|
+
*/
|
|
1316
|
+
defaultBinding?: string;
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Modal for browsing and looking up keyboard shortcuts by typing key sequences.
|
|
1320
|
+
*
|
|
1321
|
+
* Unlike SequenceModal (which auto-executes when a complete sequence is entered),
|
|
1322
|
+
* LookupModal lets you browse all available shortcuts and select one to execute.
|
|
1323
|
+
*
|
|
1324
|
+
* - Press keys to filter to matching sequences
|
|
1325
|
+
* - Use arrow keys to navigate results
|
|
1326
|
+
* - Press Enter to execute selected action
|
|
1327
|
+
* - Press Escape to close or clear filter
|
|
1328
|
+
* - Press Backspace to remove last key from filter
|
|
1329
|
+
*/
|
|
1330
|
+
declare function LookupModal({ defaultBinding }?: LookupModalProps): react_jsx_runtime.JSX.Element | null;
|
|
1331
|
+
|
|
1332
|
+
/**
|
|
1333
|
+
* Modal that appears during multi-key sequence input (e.g., `g t` for "go to table").
|
|
1334
|
+
*
|
|
1335
|
+
* When a user presses a key that starts a sequence, this modal appears showing:
|
|
1336
|
+
* - The keys pressed so far
|
|
1337
|
+
* - Available completions (what keys can come next)
|
|
1338
|
+
* - A timeout indicator
|
|
1339
|
+
*
|
|
1340
|
+
* Unlike LookupModal (which requires explicit activation and lets you browse/search),
|
|
1341
|
+
* SequenceModal appears automatically when you start typing a sequence and auto-executes
|
|
1342
|
+
* when a complete sequence is entered.
|
|
1343
|
+
*
|
|
1344
|
+
* The modal auto-dismisses if no completion is pressed within the sequence timeout,
|
|
1345
|
+
* or when the user presses Escape, or when a complete sequence is executed.
|
|
1346
|
+
*
|
|
1347
|
+
* @example
|
|
1348
|
+
* ```tsx
|
|
1349
|
+
* // Include in your app (no props needed - uses HotkeysContext)
|
|
1350
|
+
* <HotkeysProvider>
|
|
1351
|
+
* <App />
|
|
1352
|
+
* <SequenceModal />
|
|
1353
|
+
* </HotkeysProvider>
|
|
1354
|
+
* ```
|
|
1355
|
+
*/
|
|
1040
1356
|
declare function SequenceModal(): react_jsx_runtime.JSX.Element | null;
|
|
1041
1357
|
|
|
1042
|
-
interface ModifierIconProps {
|
|
1358
|
+
interface ModifierIconProps extends SVGProps<SVGSVGElement> {
|
|
1043
1359
|
className?: string;
|
|
1044
1360
|
style?: CSSProperties;
|
|
1045
1361
|
}
|
|
1046
1362
|
/** Command/Meta key icon (⌘) */
|
|
1047
|
-
declare
|
|
1363
|
+
declare const Command: react.ForwardRefExoticComponent<Omit<ModifierIconProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
|
|
1048
1364
|
/** Control key icon (^) - chevron/caret */
|
|
1049
|
-
declare
|
|
1365
|
+
declare const Ctrl: react.ForwardRefExoticComponent<Omit<ModifierIconProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
|
|
1050
1366
|
/** Shift key icon (⇧) - hollow arrow */
|
|
1051
|
-
declare
|
|
1367
|
+
declare const Shift: react.ForwardRefExoticComponent<Omit<ModifierIconProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
|
|
1052
1368
|
/** Option key icon (⌥) - macOS style */
|
|
1053
|
-
declare
|
|
1369
|
+
declare const Option: react.ForwardRefExoticComponent<Omit<ModifierIconProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
|
|
1054
1370
|
/** Alt key icon (⎇) - Windows style, though "Alt" text is more common on Windows */
|
|
1055
|
-
declare
|
|
1371
|
+
declare const Alt: react.ForwardRefExoticComponent<Omit<ModifierIconProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
|
|
1056
1372
|
type ModifierType = 'meta' | 'ctrl' | 'shift' | 'alt' | 'opt';
|
|
1057
1373
|
/** Get the appropriate icon component for a modifier key */
|
|
1058
|
-
declare function getModifierIcon(modifier: ModifierType):
|
|
1374
|
+
declare function getModifierIcon(modifier: ModifierType): typeof Command;
|
|
1059
1375
|
/** Render a modifier icon by name */
|
|
1060
|
-
declare
|
|
1376
|
+
declare const ModifierIcon: react.ForwardRefExoticComponent<Omit<ModifierIconProps & {
|
|
1061
1377
|
modifier: ModifierType;
|
|
1062
|
-
}
|
|
1378
|
+
}, "ref"> & react.RefAttributes<SVGSVGElement>>;
|
|
1379
|
+
|
|
1380
|
+
interface KeyIconProps {
|
|
1381
|
+
className?: string;
|
|
1382
|
+
style?: CSSProperties;
|
|
1383
|
+
}
|
|
1384
|
+
/** Arrow Up icon (↑) */
|
|
1385
|
+
declare function Up({ className, style }: KeyIconProps): react_jsx_runtime.JSX.Element;
|
|
1386
|
+
/** Arrow Down icon (↓) */
|
|
1387
|
+
declare function Down({ className, style }: KeyIconProps): react_jsx_runtime.JSX.Element;
|
|
1388
|
+
/** Arrow Left icon (←) */
|
|
1389
|
+
declare function Left({ className, style }: KeyIconProps): react_jsx_runtime.JSX.Element;
|
|
1390
|
+
/** Arrow Right icon (→) */
|
|
1391
|
+
declare function Right({ className, style }: KeyIconProps): react_jsx_runtime.JSX.Element;
|
|
1392
|
+
/** Enter/Return icon (↵) */
|
|
1393
|
+
declare function Enter({ className, style }: KeyIconProps): react_jsx_runtime.JSX.Element;
|
|
1394
|
+
/** Backspace icon (⌫) */
|
|
1395
|
+
declare function Backspace({ className, style }: KeyIconProps): react_jsx_runtime.JSX.Element;
|
|
1396
|
+
type KeyIconType = 'arrowup' | 'arrowdown' | 'arrowleft' | 'arrowright' | 'enter' | 'backspace';
|
|
1397
|
+
/** Get the icon component for a key, or null if no icon exists */
|
|
1398
|
+
declare function getKeyIcon(key: string): React.ComponentType<KeyIconProps> | null;
|
|
1399
|
+
|
|
1400
|
+
/**
|
|
1401
|
+
* Default timeout for key sequences (no timeout).
|
|
1402
|
+
* Set to a finite number (ms) to auto-submit sequences after that duration.
|
|
1403
|
+
*/
|
|
1404
|
+
declare const DEFAULT_SEQUENCE_TIMEOUT: number;
|
|
1405
|
+
/**
|
|
1406
|
+
* Reserved action IDs for built-in UI components.
|
|
1407
|
+
* These are registered automatically by their respective components.
|
|
1408
|
+
*/
|
|
1409
|
+
declare const ACTION_MODAL = "__hotkeys:modal";
|
|
1410
|
+
declare const ACTION_OMNIBAR = "__hotkeys:omnibar";
|
|
1411
|
+
declare const ACTION_LOOKUP = "__hotkeys:lookup";
|
|
1063
1412
|
|
|
1064
|
-
export { type ActionConfig, type ActionDefinition, type ActionRegistry, type ActionSearchResult, ActionsRegistryContext, type ActionsRegistryValue,
|
|
1413
|
+
export { ACTION_LOOKUP, ACTION_MODAL, ACTION_OMNIBAR, type ActionConfig, type ActionDefinition, type ActionHandler, type ActionRegistry, type ActionSearchResult, ActionsRegistryContext, type ActionsRegistryValue, Alt, Backspace, type BindingInfo, Command, Ctrl, DEFAULT_SEQUENCE_TIMEOUT, DIGITS_PLACEHOLDER, DIGIT_PLACEHOLDER, Down, Enter, type FuzzyMatchResult, type GroupRenderer, type GroupRendererProps, type HandlerMap, type HotkeyHandler, type HotkeyMap, type HotkeySequence, type HotkeysConfig, type HotkeysContextValue, HotkeysProvider, type HotkeysProviderProps, Kbd, KbdLookup, KbdModal, KbdOmnibar, type KbdProps, Kbds, Key, type KeyCombination, type KeyCombinationDisplay, type KeyConflict, type KeyIconProps, type KeyIconType, type KeySeq, KeybindingEditor, type KeybindingEditorProps, type KeybindingEditorRenderProps, Left, LookupModal, ModifierIcon, type ModifierIconProps, type ModifierType, type Modifiers, Omnibar, type OmnibarProps, type OmnibarRenderProps, Option, type RecordHotkeyOptions, type RecordHotkeyResult, type RegisteredAction, Right, type SeqElem, type SeqElemState, type SeqMatchState, type SequenceCompletion, SequenceModal, Shift, type ShortcutGroup, ShortcutsModal, type ShortcutsModalProps, type ShortcutsModalRenderProps, type TooltipComponent, type TooltipProps, type TwoColumnConfig, type TwoColumnRow, Up, type UseEditableHotkeysOptions, type UseEditableHotkeysResult, type UseHotkeysOptions, type UseHotkeysResult, type UseOmnibarOptions, type UseOmnibarResult, countPlaceholders, createTwoColumnRenderer, extractCaptures, findConflicts, formatBinding, formatCombination, formatKeyForDisplay, formatKeySeq, fuzzyMatch, getActionBindings, getConflictsArray, getKeyIcon, getModifierIcon, getSequenceCompletions, hasConflicts, hasDigitPlaceholders, hotkeySequenceToKeySeq, isDigitPlaceholder, isMac, isModifierKey, isPlaceholderSentinel, isSequence, isShiftedSymbol, keySeqToHotkeySequence, normalizeKey, parseCombinationId, parseHotkeyString, parseKeySeq, searchActions, useAction, useActions, useActionsRegistry, useEditableHotkeys, useHotkeys, useHotkeysContext, useMaybeHotkeysContext, useOmnibar, useRecordHotkey };
|