@inklu/keys 2.2.0 → 3.0.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 +67 -213
- package/dist/attributes.d.mts +1 -1
- package/dist/{index-DRXMJmbc.d.mts → index-BnB38jCF.d.mts} +20 -54
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +2 -2
- package/dist/react.d.mts +7 -12
- package/dist/react.mjs +9 -90
- package/dist/{src-TaZw4V61.mjs → src-CGKvYKjd.mjs} +331 -795
- package/dist/{types-D-hUKGoN.d.mts → types-BxMI3b4a.d.mts} +16 -117
- package/package.json +2 -3
|
@@ -11,12 +11,8 @@ type Letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" |
|
|
|
11
11
|
type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
|
|
12
12
|
type FunctionKey = `F${Exclude<Digit, "0">}` | `F1${Digit}` | `F2${"0" | "1" | "2" | "3" | "4"}`;
|
|
13
13
|
type Punctuation = "/" | "[" | "]" | "\\" | "=" | "-" | "," | "." | ";" | "`" | "'" | "+" | "?" | "!" | "@" | "#" | "$" | "%" | "^" | "&" | "*" | "(" | ")" | "_" | "{" | "}" | "|" | ":" | '"' | "<" | ">" | "~";
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
* `"Escape"`), or a physical key by its `KeyboardEvent.code` in brackets
|
|
17
|
-
* (`"[KeyK]"`), which stays put whatever the keyboard layout.
|
|
18
|
-
*/
|
|
19
|
-
type Key = Letter | Digit | FunctionKey | Punctuation | (typeof NAMED_KEYS)[number] | `[${string}]`;
|
|
14
|
+
/** The key of a chord: the character or named key it produces (`"K"`, `"Escape"`). */
|
|
15
|
+
type Key = Letter | Digit | FunctionKey | Punctuation | (typeof NAMED_KEYS)[number];
|
|
20
16
|
type Held<Modifier extends string> = "" | `${Modifier}+`;
|
|
21
17
|
type Modifiers = `${Held<"Control">}${Held<"Alt">}${Held<"Shift">}${Held<"Meta">}` | `Mod+${Held<"Alt">}${Held<"Shift">}`;
|
|
22
18
|
/**
|
|
@@ -53,13 +49,6 @@ type SerializedBinding = string | Array<string>;
|
|
|
53
49
|
type Json = string | number | boolean | null | ReadonlyArray<Json> | {
|
|
54
50
|
readonly [key: string]: Json;
|
|
55
51
|
};
|
|
56
|
-
/** Display options for formatting hotkeys. */
|
|
57
|
-
interface DisplayOptions {
|
|
58
|
-
/** Platform to write for. Defaults to the one detected. */
|
|
59
|
-
platform?: Platform;
|
|
60
|
-
/** Symbols such as `⌘` and `↩` rather than names such as `Cmd`. Defaults to `true`. */
|
|
61
|
-
useSymbols?: boolean;
|
|
62
|
-
}
|
|
63
52
|
/** Trigger source for a command. */
|
|
64
53
|
type CommandSource = "keyboard" | "api" | "dom";
|
|
65
54
|
/** Context passed to a command's handler. */
|
|
@@ -84,17 +73,6 @@ type CommandHandler<Id extends string = string> = (context: CommandContext<Id>)
|
|
|
84
73
|
interface CommandDefinition<Id extends string = string> {
|
|
85
74
|
/** Human-readable title. */
|
|
86
75
|
title: string;
|
|
87
|
-
/** Longer explanation, such as a palette's secondary line or a tooltip. */
|
|
88
|
-
description?: string;
|
|
89
|
-
/** Heading to list the command under in a palette or shortcut sheet, e.g. `"Navigate"`. */
|
|
90
|
-
group?: string;
|
|
91
|
-
/** Extra search terms `matchCommands` checks besides the title, e.g. `["find", "search"]`. */
|
|
92
|
-
keywords?: ReadonlyArray<string>;
|
|
93
|
-
/**
|
|
94
|
-
* Leave the command out of `matchCommands`. It still runs and still appears
|
|
95
|
-
* in `list()`. Defaults to `false`.
|
|
96
|
-
*/
|
|
97
|
-
hidden?: boolean;
|
|
98
76
|
/**
|
|
99
77
|
* Default key binding(s). Write `{ mac, other }` where the platforms'
|
|
100
78
|
* conventions differ, as they do for redo and for back and forward.
|
|
@@ -103,26 +81,11 @@ interface CommandDefinition<Id extends string = string> {
|
|
|
103
81
|
/** Scope required for this command to fire. Omit for global, or `"*"` to bypass exclusive scopes. */
|
|
104
82
|
scope?: string;
|
|
105
83
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
|
|
109
|
-
preventDefault?: boolean;
|
|
110
|
-
/**
|
|
111
|
-
* Whether to ignore key events from text inputs, selects, contenteditable
|
|
112
|
-
* elements and widgets with a text-entry ARIA role. When omitted, chords
|
|
113
|
-
* holding Control or Meta and bare `Escape` still fire there, except the
|
|
114
|
-
* field's own: select all, copy, cut, paste, undo, redo, and moving or
|
|
115
|
-
* deleting by word or line.
|
|
84
|
+
* Whether a text field keeps the keys: inputs, selects, contenteditable
|
|
85
|
+
* elements and widgets with a text-entry ARIA role. Defaults to `true`,
|
|
86
|
+
* except for `Escape`. Set `false` on a command that should fire there too.
|
|
116
87
|
*/
|
|
117
88
|
ignoreInputs?: boolean;
|
|
118
|
-
/** Timeout in milliseconds between sequence steps. Defaults to `1000`. */
|
|
119
|
-
sequenceTimeout?: number;
|
|
120
|
-
/**
|
|
121
|
-
* Whether holding the keys down runs the command again on each auto-repeat.
|
|
122
|
-
* Defaults to `true`. With `false` it runs once per press and still claims
|
|
123
|
-
* its key while held.
|
|
124
|
-
*/
|
|
125
|
-
repeat?: boolean;
|
|
126
89
|
/**
|
|
127
90
|
* What the command does, when that needs nothing a component owns. Otherwise
|
|
128
91
|
* attach it with `commands.handle()` or `useCommandHandler`. A command with
|
|
@@ -134,12 +97,6 @@ interface CommandDefinition<Id extends string = string> {
|
|
|
134
97
|
interface Command<Id extends string = string> {
|
|
135
98
|
readonly id: Id;
|
|
136
99
|
readonly title: string;
|
|
137
|
-
readonly description?: string;
|
|
138
|
-
readonly group?: string;
|
|
139
|
-
/** Extra search terms; empty when the definition gave none. */
|
|
140
|
-
readonly keywords: ReadonlyArray<string>;
|
|
141
|
-
/** Whether `matchCommands` leaves the command out. */
|
|
142
|
-
readonly hidden: boolean;
|
|
143
100
|
readonly scope?: string;
|
|
144
101
|
/** Active bindings after user overrides. */
|
|
145
102
|
readonly bindings: ReadonlyArray<Binding>;
|
|
@@ -149,37 +106,21 @@ interface Command<Id extends string = string> {
|
|
|
149
106
|
readonly tokens: ReadonlyArray<ReadonlyArray<string>>;
|
|
150
107
|
/** Value for the `aria-keyshortcuts` attribute. Chords only: it cannot express a sequence. */
|
|
151
108
|
readonly aria: string;
|
|
152
|
-
/**
|
|
153
|
-
* Every binding phrased for a screen reader, joined by `" or "`: `"Command K"`,
|
|
154
|
-
* `"G then I"`. The only accessible form of a sequence.
|
|
155
|
-
*/
|
|
156
|
-
readonly spoken: string;
|
|
157
109
|
/** Whether its keys work right now: it has a handler and its scope is active. */
|
|
158
110
|
readonly reachable: boolean;
|
|
159
111
|
/** Whether the command has a user keymap override. */
|
|
160
112
|
readonly overridden: boolean;
|
|
161
113
|
}
|
|
162
|
-
/** A user's change to one command: `"replace"` the default (`[]` unbinds), or `"add"` to it. */
|
|
163
|
-
interface Override {
|
|
164
|
-
readonly kind: "replace" | "add";
|
|
165
|
-
readonly bindings: ReadonlyArray<Binding>;
|
|
166
|
-
}
|
|
167
114
|
/** Where user overrides are kept between visits. `webStorage()` makes one. */
|
|
168
115
|
interface KeymapStore {
|
|
169
|
-
/** The stored overrides: empty when there are none, `null` when they cannot be read. */
|
|
170
|
-
read(): Map<string,
|
|
171
|
-
write(overrides: ReadonlyMap<string,
|
|
172
|
-
/** Calls `onChange` when another tab writes. Returns a function that stops. */
|
|
173
|
-
watch(onChange: () => void): () => void;
|
|
116
|
+
/** The stored overrides by command id: empty when there are none, `null` when they cannot be read. */
|
|
117
|
+
read(): Map<string, ReadonlyArray<Binding>> | null;
|
|
118
|
+
write(overrides: ReadonlyMap<string, ReadonlyArray<Binding>>): void;
|
|
174
119
|
}
|
|
175
|
-
/** One command's stored override: an array replaces the default, `{ add }` extends it. */
|
|
176
|
-
type SerializedOverride = Array<SerializedBinding> | {
|
|
177
|
-
add: Array<SerializedBinding>;
|
|
178
|
-
};
|
|
179
120
|
/** User overrides as JSON-safe data, keyed by command id. What `exportKeymap()` returns. */
|
|
180
121
|
type SerializedKeymap = {
|
|
181
122
|
version: 1;
|
|
182
|
-
overrides: Record<string,
|
|
123
|
+
overrides: Record<string, Array<SerializedBinding>>;
|
|
183
124
|
};
|
|
184
125
|
/** A registry's keymap: the keys in effect, and the user's changes to them. */
|
|
185
126
|
interface CommandKeymap<Id extends string = string> {
|
|
@@ -187,19 +128,14 @@ interface CommandKeymap<Id extends string = string> {
|
|
|
187
128
|
get(id: Id): ReadonlyArray<Binding>;
|
|
188
129
|
/** Replaces a command's bindings. `null` unbinds it; exactly the default forgets the override. */
|
|
189
130
|
set(id: Id, input: BindingInput | null): void;
|
|
190
|
-
/** Appends a binding, stored on top of the default so a default that changes still applies. */
|
|
191
|
-
add(id: Id, input: BindingInput): void;
|
|
192
131
|
/** Resets user overrides back to defaults for a specific command or all commands. */
|
|
193
132
|
reset(id?: Id): void;
|
|
194
133
|
}
|
|
195
134
|
/**
|
|
196
|
-
*
|
|
197
|
-
* same keys (`"exact"`) or
|
|
198
|
-
* or the browser or operating system keeping the keys (`"reserved"`, which
|
|
199
|
-
* has no `id`).
|
|
135
|
+
* A command in an overlapping scope whose keys stand in a binding's way: the
|
|
136
|
+
* same keys (`"exact"`), or one binding starting the other (`"prefix"`).
|
|
200
137
|
*/
|
|
201
|
-
|
|
202
|
-
/** Whether the bindings are identical or one is a prefix of the other. */
|
|
138
|
+
interface Conflict<Id extends string = string> {
|
|
203
139
|
readonly kind: "exact" | "prefix";
|
|
204
140
|
/** ID of the conflicting command. */
|
|
205
141
|
readonly id: Id;
|
|
@@ -209,13 +145,7 @@ type Conflict<Id extends string = string> = {
|
|
|
209
145
|
readonly display: string;
|
|
210
146
|
/** The conflicting command's scope, if it has one. */
|
|
211
147
|
readonly scope?: string;
|
|
212
|
-
}
|
|
213
|
-
readonly kind: "reserved";
|
|
214
|
-
/** The binding that was asked about. */
|
|
215
|
-
readonly binding: Binding;
|
|
216
|
-
/** Formatted display representation of that binding. */
|
|
217
|
-
readonly display: string;
|
|
218
|
-
};
|
|
148
|
+
}
|
|
219
149
|
/** Options for conflict detection. */
|
|
220
150
|
interface ConflictOptions<Id extends string = string> {
|
|
221
151
|
/** Command ID to ignore during conflict checking. */
|
|
@@ -245,19 +175,6 @@ interface RunOptions {
|
|
|
245
175
|
* handler to it, or its scope is not open.
|
|
246
176
|
*/
|
|
247
177
|
type RunBlockReason = "unknown" | "unhandled" | "out-of-scope";
|
|
248
|
-
/** Represents a partially completed key sequence. */
|
|
249
|
-
interface PendingSequence<Id extends string = string> {
|
|
250
|
-
/** Command ID. */
|
|
251
|
-
readonly id: Id;
|
|
252
|
-
/** Sequence binding being typed. */
|
|
253
|
-
readonly binding: SequenceBinding;
|
|
254
|
-
/** Number of steps matched so far. */
|
|
255
|
-
readonly matched: number;
|
|
256
|
-
/** Total steps in the sequence. */
|
|
257
|
-
readonly total: number;
|
|
258
|
-
/** Formatted remaining steps. */
|
|
259
|
-
readonly remaining: ReadonlyArray<string>;
|
|
260
|
-
}
|
|
261
178
|
/** Configuration options for a commands registry. */
|
|
262
179
|
interface CommandsOptions<Id extends string = string> {
|
|
263
180
|
/**
|
|
@@ -275,8 +192,6 @@ interface CommandsOptions<Id extends string = string> {
|
|
|
275
192
|
bindings?: Partial<Record<Id, BindingInput | PlatformBindings | null>>;
|
|
276
193
|
/** Platform for modifier resolution and display formatting. Defaults to auto-detection. */
|
|
277
194
|
platform?: Platform;
|
|
278
|
-
/** Target element for key events. Defaults to `document`. */
|
|
279
|
-
target?: HTMLElement | Document | Window | null;
|
|
280
195
|
/**
|
|
281
196
|
* Where to keep user keymap overrides between visits, such as
|
|
282
197
|
* `webStorage("my-app.keys")`. They load on the first `mount()`, so the
|
|
@@ -289,15 +204,8 @@ interface CommandsOptions<Id extends string = string> {
|
|
|
289
204
|
* `true`. WCAG 2.1.4 requires a way to turn them off.
|
|
290
205
|
*/
|
|
291
206
|
singleKeyShortcuts?: boolean;
|
|
292
|
-
/**
|
|
293
|
-
display?: DisplayOptions;
|
|
294
|
-
/** Called whenever a command runs. */
|
|
207
|
+
/** Called before any command runs, for logging or analytics. */
|
|
295
208
|
onRun?: (context: CommandContext<Id>) => void;
|
|
296
|
-
/**
|
|
297
|
-
* Error handler called when a handler or `onRun` throws. Defaults to
|
|
298
|
-
* `console.error`.
|
|
299
|
-
*/
|
|
300
|
-
onError?: (error: Error, context: CommandContext<Id>) => void;
|
|
301
209
|
}
|
|
302
210
|
/** The commands registry. */
|
|
303
211
|
interface Commands<Id extends string = string> {
|
|
@@ -317,8 +225,6 @@ interface Commands<Id extends string = string> {
|
|
|
317
225
|
* barriers, which silence keys, not commands.
|
|
318
226
|
*/
|
|
319
227
|
run(id: Id, options?: RunOptions): boolean;
|
|
320
|
-
/** Checks whether `run` would execute the command right now. */
|
|
321
|
-
canRun(id: Id): boolean;
|
|
322
228
|
/** Returns why `run` would refuse the command, or `null` if it would run. */
|
|
323
229
|
whyNotRun(id: Id): RunBlockReason | null;
|
|
324
230
|
/**
|
|
@@ -333,15 +239,8 @@ interface Commands<Id extends string = string> {
|
|
|
333
239
|
* keypress goes to `onKey` and no command runs.
|
|
334
240
|
*/
|
|
335
241
|
capture(onKey: KeyCapture): () => void;
|
|
336
|
-
/**
|
|
337
|
-
* Finds what stands in a binding's way: the platform reserving it (listed
|
|
338
|
-
* first), then commands in overlapping scopes with colliding keys.
|
|
339
|
-
*/
|
|
242
|
+
/** Finds the commands in overlapping scopes whose keys collide with a binding. */
|
|
340
243
|
conflicts(binding: BindingInput, options?: ConflictOptions<Id>): Array<Conflict<Id>>;
|
|
341
|
-
/** Returns the partially-typed sequences. Tracked only while something is subscribed. */
|
|
342
|
-
pending(): ReadonlyArray<PendingSequence<Id>>;
|
|
343
|
-
/** Subscribes to sequence progress changes. */
|
|
344
|
-
subscribePending(listener: () => void): () => void;
|
|
345
244
|
/** Starts listening for key events. Returns an unmount function. */
|
|
346
245
|
mount(): () => void;
|
|
347
246
|
/** Subscribes to registry changes. Returns an unsubscribe function. */
|
|
@@ -354,4 +253,4 @@ interface Commands<Id extends string = string> {
|
|
|
354
253
|
destroy(): void;
|
|
355
254
|
}
|
|
356
255
|
//#endregion
|
|
357
|
-
export {
|
|
256
|
+
export { Chord as C, SerializedKeymap as S, Platform as T, RunBlockReason as _, CommandDefinition as a, SequenceBinding as b, CommandSource as c, Conflict as d, ConflictOptions as f, PlatformBindings as g, KeymapStore as h, CommandContext as i, Commands as l, KeyCapture as m, BindingInput as n, CommandHandler as o, Json as p, Command as r, CommandKeymap as s, Binding as t, CommandsOptions as u, RunOptions as v, Key as w, SerializedBinding as x, ScopeOptions as y };
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inklu/keys",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A command system for the web
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "A command system for the web: typed commands, portable keybindings, scopes, sequences, conflict detection, rebinding and platform-aware display.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
7
|
-
"command-palette",
|
|
8
7
|
"commands",
|
|
9
8
|
"hotkeys",
|
|
10
9
|
"keybindings",
|