use-kbd 0.3.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 ADDED
@@ -0,0 +1,216 @@
1
+ # use-kbd
2
+
3
+ [![npm version](https://img.shields.io/npm/v/use-kbd.svg)](https://www.npmjs.com/package/use-kbd)
4
+
5
+ React library for keyboard-accessible web applications with:
6
+
7
+ 1. **Drop-in UI components** (`ShortcutsModal`, `Omnibar`, `SequenceModal`) at the App level
8
+ 2. **Minimal-boilerplate action registration** via `useAction` hook, colocated with handlers
9
+ 3. **CSS variables** for easy theming customization
10
+
11
+ Try "?" or "⌘-K" at:
12
+ - [ctbk.dev]
13
+ - [awair.runsascoded.com]
14
+
15
+ ## Inspiration
16
+ - macOS (⌘-/) and GDrive (⌥-/) menu search
17
+ - [Superhuman] omnibar
18
+ - Android searchable settings
19
+ - [Vimium] keyboard-driven browsing.
20
+
21
+ [ctbk.dev]: https://ctbk.dev
22
+ [awair.runsascoded.com]: https://awair.runsascoded.com
23
+ [Superhuman]: https://superhuman.com
24
+ [Vimium]: https://github.com/philc/vimium
25
+
26
+ ## Quick Start
27
+
28
+ ```tsx
29
+ import { HotkeysProvider, ShortcutsModal, Omnibar, SequenceModal, useAction } from 'use-kbd'
30
+ import 'use-kbd/styles.css'
31
+
32
+ function App() {
33
+ return (
34
+ <HotkeysProvider>
35
+ {/* Your app content */}
36
+ <Dashboard />
37
+ {/* Drop-in UI components */}
38
+ <ShortcutsModal />
39
+ <Omnibar />
40
+ <SequenceModal />
41
+ </HotkeysProvider>
42
+ )
43
+ }
44
+
45
+ function Dashboard() {
46
+ const { save, exportData } = useDocument()
47
+
48
+ useAction('doc:save', {
49
+ label: 'Save document',
50
+ group: 'Document',
51
+ defaultBindings: ['meta+s'],
52
+ handler: save,
53
+ })
54
+
55
+ useAction('doc:export', {
56
+ label: 'Export data',
57
+ group: 'Document',
58
+ defaultBindings: ['meta+e'],
59
+ handler: exportData,
60
+ })
61
+
62
+ return <Editor />
63
+ }
64
+ ```
65
+
66
+ Press `?` to see the shortcuts modal, or `⌘K` to open the omnibar.
67
+
68
+ ## Installation
69
+
70
+ ```bash
71
+ pnpm add use-kbd
72
+ ```
73
+
74
+ ## Core Concepts
75
+
76
+ ### Actions
77
+
78
+ Register any function with `useAction`:
79
+
80
+ ```tsx
81
+ useAction('view:toggle-sidebar', {
82
+ label: 'Toggle sidebar',
83
+ group: 'View',
84
+ defaultBindings: ['meta+b', 'meta+\\'],
85
+ keywords: ['panel', 'navigation'],
86
+ handler: () => setSidebarOpen(prev => !prev),
87
+ })
88
+ ```
89
+
90
+ Actions automatically unregister when the component unmounts—no cleanup needed.
91
+
92
+ ### Sequences
93
+
94
+ Multi-key sequences like Vim's `g g` (go to top) are supported:
95
+
96
+ ```tsx
97
+ useAction('nav:top', {
98
+ label: 'Go to top',
99
+ defaultBindings: ['g g'], // Press g, then g again
100
+ handler: () => scrollToTop(),
101
+ })
102
+ ```
103
+
104
+ The `SequenceModal` shows available completions while typing a sequence.
105
+
106
+ ### User Customization
107
+
108
+ Users can edit bindings in the `ShortcutsModal`. Changes persist to localStorage using the `storageKey` you provide.
109
+
110
+ ## Components
111
+
112
+ ### `<HotkeysProvider>`
113
+
114
+ Wrap your app to enable the hotkeys system:
115
+
116
+ ```tsx
117
+ <HotkeysProvider config={{
118
+ storageKey: 'use-kbd', // localStorage key for user overrides (default)
119
+ modalTrigger: '?', // Open shortcuts modal (default; false to disable)
120
+ omnibarTrigger: 'meta+k', // Open omnibar (default; false to disable)
121
+ sequenceTimeout: 1000, // ms before sequence times out (default)
122
+ }}>
123
+ {children}
124
+ </HotkeysProvider>
125
+ ```
126
+
127
+ ### `<ShortcutsModal>`
128
+
129
+ Displays all registered actions grouped by category. Users can click bindings to edit them.
130
+
131
+ ```tsx
132
+ <ShortcutsModal groups={[
133
+ { id: 'nav', label: 'Navigation' },
134
+ { id: 'edit', label: 'Editing' },
135
+ ]} />
136
+ ```
137
+
138
+ ### `<Omnibar>`
139
+
140
+ Command palette for searching and executing actions:
141
+
142
+ ```tsx
143
+ <Omnibar
144
+ placeholder="Type a command..."
145
+ maxResults={10}
146
+ />
147
+ ```
148
+
149
+ ### `<SequenceModal>`
150
+
151
+ Shows pending keys and available completions during sequence input. No props needed—it reads from context.
152
+
153
+ ```tsx
154
+ <SequenceModal />
155
+ ```
156
+
157
+ ## Styling
158
+
159
+ Import the default styles:
160
+
161
+ ```tsx
162
+ import 'use-kbd/styles.css'
163
+ ```
164
+
165
+ Customize with CSS variables:
166
+
167
+ ```css
168
+ .kbd-modal,
169
+ .kbd-omnibar,
170
+ .kbd-sequence {
171
+ --kbd-bg: #1f2937;
172
+ --kbd-text: #f3f4f6;
173
+ --kbd-border: #4b5563;
174
+ --kbd-accent: #3b82f6;
175
+ --kbd-kbd-bg: #374151;
176
+ }
177
+ ```
178
+
179
+ Dark mode is automatically applied via `[data-theme="dark"]` or `.dark` selectors.
180
+
181
+ See [awair's use-kbd-demo branch] for a real-world integration example.
182
+
183
+ [awair's use-kbd-demo branch]: https://github.com/runsascoded/awair/compare/use-kbd-demo~1...use-kbd-demo
184
+
185
+ ## Low-Level Hooks
186
+
187
+ For advanced use cases, the underlying hooks are also exported:
188
+
189
+ ### `useHotkeys(keymap, handlers, options?)`
190
+
191
+ Register shortcuts directly without the provider:
192
+
193
+ ```tsx
194
+ useHotkeys(
195
+ { 't': 'setTemp', 'meta+s': 'save' },
196
+ { setTemp: () => setMetric('temp'), save: handleSave }
197
+ )
198
+ ```
199
+
200
+ ### `useRecordHotkey(options?)`
201
+
202
+ Capture key combinations from user input:
203
+
204
+ ```tsx
205
+ const { isRecording, startRecording, display } = useRecordHotkey({
206
+ onCapture: (sequence, display) => saveBinding(display.id),
207
+ })
208
+ ```
209
+
210
+ ### `useEditableHotkeys(defaults, handlers, options?)`
211
+
212
+ Wraps `useHotkeys` with localStorage persistence and conflict detection.
213
+
214
+ ## License
215
+
216
+ MIT