@joewinke/jatui 0.26.0 → 0.27.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/CLAUDE.md +106 -1
- package/dist/actions/keyboardScope.d.ts +58 -0
- package/dist/actions/keyboardScope.js +110 -0
- package/dist/actions/listNav.d.ts +48 -3
- package/dist/actions/listNav.js +267 -77
- package/dist/actions/longpress.d.ts +37 -0
- package/dist/actions/longpress.js +105 -0
- package/dist/actions/stickToBottom.d.ts +66 -0
- package/dist/actions/stickToBottom.js +155 -0
- package/dist/actions/swipe.d.ts +64 -0
- package/dist/actions/swipe.js +179 -0
- package/dist/components/BottomSheet.svelte +280 -0
- package/dist/components/BottomSheet.svelte.d.ts +27 -0
- package/dist/components/ConfirmDialog.svelte +21 -0
- package/dist/components/ConfirmDialog.svelte.d.ts +11 -1
- package/dist/components/ConfirmModal.svelte +15 -0
- package/dist/components/ConfirmModal.svelte.d.ts +5 -0
- package/dist/components/Drawer.svelte +18 -1
- package/dist/components/Drawer.svelte.d.ts +9 -1
- package/dist/components/InputDialog.svelte +21 -0
- package/dist/components/InputDialog.svelte.d.ts +11 -1
- package/dist/components/Modal.svelte +18 -1
- package/dist/components/Modal.svelte.d.ts +8 -0
- package/dist/components/basic/Empty.svelte +173 -9
- package/dist/components/basic/Empty.svelte.d.ts +50 -1
- package/dist/components/basic/ErrorState.svelte +128 -0
- package/dist/components/basic/ErrorState.svelte.d.ts +46 -0
- package/dist/components/basic/JumpToLatest.svelte +60 -0
- package/dist/components/basic/JumpToLatest.svelte.d.ts +9 -0
- package/dist/components/basic/PageHeader.svelte +216 -0
- package/dist/components/basic/PageHeader.svelte.d.ts +52 -0
- package/dist/components/basic/ProgressButton.svelte +221 -0
- package/dist/components/basic/ProgressButton.svelte.d.ts +63 -0
- package/dist/components/graph/GraphApiBridge.svelte +36 -0
- package/dist/components/graph/GraphApiBridge.svelte.d.ts +9 -0
- package/dist/components/graph/GraphCanvas.svelte +212 -27
- package/dist/components/graph/GraphCanvas.svelte.d.ts +113 -19
- package/dist/components/graph/api.d.ts +52 -0
- package/dist/components/graph/api.js +66 -0
- package/dist/components/graph/index.d.ts +2 -0
- package/dist/components/graph/index.js +1 -0
- package/dist/components/graph/theme.js +13 -0
- package/dist/components/messaging/MessageItem.svelte +5 -0
- package/dist/components/messaging/MessageItem.svelte.d.ts +7 -0
- package/dist/components/table/DataTable.svelte +452 -78
- package/dist/components/table/DataTable.svelte.d.ts +2 -2
- package/dist/components/table/ManageColumnsDropdown.svelte +466 -0
- package/dist/components/table/ManageColumnsDropdown.svelte.d.ts +26 -0
- package/dist/components/table/columnStorage.d.ts +29 -0
- package/dist/components/table/columnStorage.js +61 -0
- package/dist/components/table/groupRows.d.ts +72 -0
- package/dist/components/table/groupRows.js +118 -0
- package/dist/components/table/index.d.ts +7 -1
- package/dist/components/table/index.js +3 -0
- package/dist/components/table/types.d.ts +121 -20
- package/dist/index.d.ts +25 -2
- package/dist/index.js +32 -1
- package/dist/utils/ansiToHtml.d.ts +83 -0
- package/dist/utils/ansiToHtml.js +543 -0
- package/dist/utils/keyboardShortcutRegistry.d.ts +332 -11
- package/dist/utils/keyboardShortcutRegistry.js +1070 -76
- package/dist/utils/pollBackoff.d.ts +83 -0
- package/dist/utils/pollBackoff.js +151 -0
- package/dist/utils/snapFlick.d.ts +59 -0
- package/dist/utils/snapFlick.js +66 -0
- package/dist/video/advisors/qr.d.ts +1 -1
- package/dist/virtual/createRowWindow.d.ts +75 -0
- package/dist/virtual/createRowWindow.js +129 -0
- package/dist/virtual/index.d.ts +4 -0
- package/dist/virtual/index.js +5 -0
- package/dist/virtual/rowWindowCore.d.ts +202 -0
- package/dist/virtual/rowWindowCore.js +510 -0
- package/package.json +11 -1
|
@@ -37,18 +37,64 @@
|
|
|
37
37
|
* browser (Chrome won't hand some of them to the page at all). The sidebar
|
|
38
38
|
* convention across JAT apps is `mod+\` — see `SIDEBAR_TOGGLE_KEY`.
|
|
39
39
|
*
|
|
40
|
+
* Rebinding (jatui-voc3i.1): a definition with an `id` is rebindable. Its
|
|
41
|
+
* `key` is the DEFAULT; the effective binding is the user's override from a
|
|
42
|
+
* `BindingStore` (or `rebind()`), and registered entries re-resolve on every
|
|
43
|
+
* binding change, so components never re-register because a key moved.
|
|
44
|
+
* `declare()` makes ids known before their component mounts (a settings page
|
|
45
|
+
* can list a route's shortcuts without visiting the route). Combos are
|
|
46
|
+
* stored and compared in the canonical form `normalizeCombo()` produces.
|
|
47
|
+
* A stored entry that can't be parsed is never dropped silently: it is
|
|
48
|
+
* logged once (`console.warn`) and listed by `rejectedBindings()` with its
|
|
49
|
+
* raw value, so a settings page can show it.
|
|
50
|
+
*
|
|
51
|
+
* Conflicts (jatui-voc3i.2): `findConflicts(keys, { id | context })` and
|
|
52
|
+
* `allConflicts()` report collisions by how the stack resolves keys — same
|
|
53
|
+
* context is an error (one of them is dead), contexts that can be co-active
|
|
54
|
+
* (`contextGraph`; `global` is beneath everything) shadow with a warning, a
|
|
55
|
+
* modal upper context is info (they never compete), and `reserved`
|
|
56
|
+
* browser combos carry their own severity. `rebind()` rejects on any error.
|
|
57
|
+
*
|
|
58
|
+
* Beyond combos (jatui-voc3i.3): `onRelease` fires on the keyup of the
|
|
59
|
+
* same physical key (push-to-talk); `onModifierChange` reports held
|
|
60
|
+
* modifiers and is reset on blur; `registerHandler()` adds raw handlers
|
|
61
|
+
* (count prefixes, chords) that run inside the context walk after the
|
|
62
|
+
* context's combos, so modals still suppress them; `pushContext` takes a
|
|
63
|
+
* `layer` (frames sort by layer, then push order) and, for modal frames, a
|
|
64
|
+
* `passthrough` list of ids/combos that still reach the contexts beneath.
|
|
65
|
+
*
|
|
66
|
+
* Known divergences from the JAT IDE's legacy `shortcutParser` (an importer
|
|
67
|
+
* passed to `localStorageBindingStore({ migrate })` must account for them):
|
|
68
|
+
* - `cmd`: the IDE maps `Cmd+K` to META on every platform; here `cmd` is
|
|
69
|
+
* an alias of `mod` (Ctrl on Linux/Windows). Rewrite `cmd` → `meta`
|
|
70
|
+
* when importing so a stored `Cmd+K` keeps meaning ⌘/Win.
|
|
71
|
+
* - Physical-key fallback: the IDE falls back to `event.code` for LETTER
|
|
72
|
+
* keys under any modifier (non-Latin layouts: Ctrl+K on a Cyrillic
|
|
73
|
+
* layout). Here the `event.code` fallback applies only to alt combos and
|
|
74
|
+
* to `` ` `` / Space; `ctrl+k` does not fire for `ctrl+л`.
|
|
75
|
+
*
|
|
40
76
|
* Pure TypeScript, no Svelte runes and no DOM globals at import time, so it
|
|
41
77
|
* is SSR-safe and unit-testable under plain node.
|
|
42
78
|
*/
|
|
43
79
|
export type ShortcutModifier = 'mod' | 'meta' | 'ctrl' | 'shift' | 'alt' | 'cmd';
|
|
44
80
|
export type ShortcutPlatform = 'mac' | 'other';
|
|
45
81
|
export interface ShortcutDefinition {
|
|
82
|
+
/**
|
|
83
|
+
* Stable id. Required for rebinding and conflict reporting; optional
|
|
84
|
+
* otherwise. Registering one id twice in one context throws in
|
|
85
|
+
* dev and warns in prod (the later registration wins).
|
|
86
|
+
*/
|
|
87
|
+
id?: string;
|
|
46
88
|
/**
|
|
47
89
|
* `KeyboardEvent.key` value (case-insensitive for letters), optionally
|
|
48
90
|
* prefixed with modifiers: `'k'`, `'mod+k'`, `'shift+ArrowDown'`, `'?'`,
|
|
49
|
-
* `'mod+\\'`. Use `'+'` / `'mod++'` for the plus key itself.
|
|
91
|
+
* `'mod+\\'`. Use `'+'` / `'mod++'` for the plus key itself. An array
|
|
92
|
+
* binds several combos that all fire the action (`['j', 'ArrowDown']`).
|
|
93
|
+
* With an `id`, this is the default binding.
|
|
50
94
|
*/
|
|
51
|
-
key: string;
|
|
95
|
+
key: string | string[];
|
|
96
|
+
/** May the user rebind it? Default: true when `id` is set, false otherwise. */
|
|
97
|
+
rebindable?: boolean;
|
|
52
98
|
/** Extra modifiers, merged with any parsed from `key`. `cmd` is an alias of `mod`. */
|
|
53
99
|
modifiers?: ShortcutModifier | ShortcutModifier[];
|
|
54
100
|
/** Shown in the overlay. */
|
|
@@ -70,12 +116,62 @@ export interface ShortcutDefinition {
|
|
|
70
116
|
hidden?: boolean;
|
|
71
117
|
/** Overrides the computed keycap label in the overlay (e.g. `'j / ↓'`). */
|
|
72
118
|
label?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Called on the `keyup` of the same PHYSICAL key (`event.code`) after this
|
|
121
|
+
* shortcut fired — whatever modifiers are still down, because on Linux an
|
|
122
|
+
* IME often swallows Ctrl before the keyup arrives. Push-to-talk is the
|
|
123
|
+
* use case. Needs `attach()` (or `handleKeyup`). A blur of the attached
|
|
124
|
+
* target clears the pending release WITHOUT calling it.
|
|
125
|
+
*/
|
|
126
|
+
onRelease?: (event: KeyboardEvent) => void;
|
|
73
127
|
}
|
|
74
128
|
export interface PushContextOptions {
|
|
75
129
|
/** Suppress every context beneath this one (including `global`) while pushed. */
|
|
76
130
|
modal?: boolean;
|
|
77
131
|
/** Overlay section title for this context. Default: the context name. */
|
|
78
132
|
label?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Modal only: shortcuts from the contexts beneath that still fire while
|
|
135
|
+
* this frame is pushed (a session overlay that keeps `mod+\\`). Each entry
|
|
136
|
+
* is a shortcut id or a combo; a combo matches physically against the
|
|
137
|
+
* lower entry's live binding. Raw handlers never pass through.
|
|
138
|
+
*/
|
|
139
|
+
passthrough?: string[];
|
|
140
|
+
/**
|
|
141
|
+
* Stacking layer, default 0. Frames sort by layer, then push order, so an
|
|
142
|
+
* app-level surface pushed at `layer: 1` (a peek drawer, a command line)
|
|
143
|
+
* stays above any route context that mounts after it.
|
|
144
|
+
*/
|
|
145
|
+
layer?: number;
|
|
146
|
+
}
|
|
147
|
+
/** Modifier keys currently held, as reported to `onModifierChange`. */
|
|
148
|
+
export interface ModifierState {
|
|
149
|
+
alt: boolean;
|
|
150
|
+
ctrl: boolean;
|
|
151
|
+
shift: boolean;
|
|
152
|
+
meta: boolean;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Key handling that isn't a set of combos (count prefixes like `5j`, chords
|
|
156
|
+
* like `m<letter>`, `Alt+1..9` with an index). Runs INSIDE the context walk —
|
|
157
|
+
* after the context's combos — so a modal context still suppresses it. Never
|
|
158
|
+
* rebindable, never part of conflict detection.
|
|
159
|
+
*/
|
|
160
|
+
export interface RawShortcutHandler {
|
|
161
|
+
/** Context this handler belongs to. Default `'global'`. */
|
|
162
|
+
context?: string;
|
|
163
|
+
/** Return true when the event was handled: the walk stops and `preventDefault` is applied (unless opted out). */
|
|
164
|
+
handle: (event: KeyboardEvent) => boolean;
|
|
165
|
+
/** Called even while focus is in a text field. Default false. */
|
|
166
|
+
allowInInput?: boolean;
|
|
167
|
+
/** Call `preventDefault()` when `handle` returns true. Default true. */
|
|
168
|
+
preventDefault?: boolean;
|
|
169
|
+
/** Overlay rows this handler contributes (e.g. `{ key: 'm<letter>', description: 'Set mark' }`). */
|
|
170
|
+
describe?: () => {
|
|
171
|
+
key: string;
|
|
172
|
+
description: string;
|
|
173
|
+
group?: string;
|
|
174
|
+
}[];
|
|
79
175
|
}
|
|
80
176
|
/** Same shape as `KeyboardShortcutsOverlay`'s `ShortcutSection`. */
|
|
81
177
|
export interface RegistrySection {
|
|
@@ -94,6 +190,12 @@ export interface ToSectionsOptions {
|
|
|
94
190
|
scope?: 'active' | 'all';
|
|
95
191
|
/** Drop shortcuts whose `enabled()` currently returns false. Default false. */
|
|
96
192
|
onlyEnabled?: boolean;
|
|
193
|
+
/**
|
|
194
|
+
* Also list `declare()`d ids that no mounted component has registered yet
|
|
195
|
+
* (a route's shortcuts before the route is visited). With `scope: 'active'`
|
|
196
|
+
* only declarations in live contexts count. Default false.
|
|
197
|
+
*/
|
|
198
|
+
includeDeclared?: boolean;
|
|
97
199
|
}
|
|
98
200
|
export interface ShortcutRegistryOptions {
|
|
99
201
|
/** Force the platform (tests, SSR). Default: sniffed from `navigator`. */
|
|
@@ -102,11 +204,148 @@ export interface ShortcutRegistryOptions {
|
|
|
102
204
|
contextLabels?: Record<string, string>;
|
|
103
205
|
/** Called when an action throws or rejects. Default: `console.error`. */
|
|
104
206
|
onError?: (error: unknown, shortcut: ShortcutDefinition) => void;
|
|
207
|
+
/** Where user overrides live. Without one, bindings are in-memory only. */
|
|
208
|
+
bindings?: BindingStore;
|
|
209
|
+
/**
|
|
210
|
+
* Throw on programming errors (duplicate id in one context) instead of
|
|
211
|
+
* warning. Default: `import.meta.env.DEV`, else `NODE_ENV !== 'production'`.
|
|
212
|
+
*/
|
|
213
|
+
dev?: boolean;
|
|
214
|
+
/** Combos the browser or OS owns. Default: `BROWSER_RESERVED_COMBOS`. Pass `[]` to opt out. */
|
|
215
|
+
reserved?: ReservedCombo[];
|
|
216
|
+
/**
|
|
217
|
+
* Which contexts can be on the stack at the same time: `context → contexts
|
|
218
|
+
* it can sit ABOVE`. Transitive, and `global` is beneath everything. The IDE
|
|
219
|
+
* declares e.g. `{ 'route:tasks': ['global'], 'task-detail': ['route:tasks', 'route:inbox'] }`.
|
|
220
|
+
* Without it, every non-global context counts as co-active with `global` only.
|
|
221
|
+
*/
|
|
222
|
+
contextGraph?: Record<string, string[]>;
|
|
223
|
+
/**
|
|
224
|
+
* Contexts that are always pushed `{ modal: true }`, for conflict reporting
|
|
225
|
+
* before they are ever pushed (a catalogue checked in a test). A context
|
|
226
|
+
* pushed modal at runtime is remembered as modal automatically.
|
|
227
|
+
*/
|
|
228
|
+
modalContexts?: string[];
|
|
229
|
+
/**
|
|
230
|
+
* Replaces the "is this keystroke text entry?" test (default: the exported
|
|
231
|
+
* `isTypingTarget`). Compose with it to add editor hosts:
|
|
232
|
+
* `(t, e) => isTypingTarget(t) || !!(t as Element)?.closest?.('.monaco-editor')`.
|
|
233
|
+
*/
|
|
234
|
+
isTypingTarget?: (target: EventTarget | null, event: KeyboardEvent) => boolean;
|
|
235
|
+
/**
|
|
236
|
+
* Called whenever the set of held modifiers changes (seen on keydown and
|
|
237
|
+
* keyup), and with everything released when the attached target blurs —
|
|
238
|
+
* so an Alt-held hint layer can't get stuck after Alt+Tab.
|
|
239
|
+
*/
|
|
240
|
+
onModifierChange?: (state: ModifierState) => void;
|
|
105
241
|
}
|
|
106
|
-
/**
|
|
242
|
+
/** A combo the browser or OS owns. `block`: never delivered to the page; `warn`: delivered, but overriding it surprises users. */
|
|
243
|
+
export interface ReservedCombo {
|
|
244
|
+
/** Combo in registry syntax (`'mod+t'`). Compared physically on the registry's platform. */
|
|
245
|
+
key: string;
|
|
246
|
+
reason: string;
|
|
247
|
+
severity: 'block' | 'warn';
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Browser-owned combos. `mod+t/w/n` block: Chrome
|
|
251
|
+
* never hands them to the page. The editing/navigation combos (and Ctrl+B,
|
|
252
|
+
* the bookmarks bar) are delivered but warn.
|
|
253
|
+
*/
|
|
254
|
+
export declare const BROWSER_RESERVED_COMBOS: ReservedCombo[];
|
|
255
|
+
/** Sparse user overrides: id → canonical combos. `[]` means "explicitly unbound". Missing id = default. */
|
|
256
|
+
export type BindingOverrides = Record<string, string[]>;
|
|
257
|
+
export interface BindingStore {
|
|
258
|
+
load(): BindingOverrides | Promise<BindingOverrides>;
|
|
259
|
+
save(overrides: BindingOverrides): void | Promise<void>;
|
|
260
|
+
/** Optional: another tab/device changed the bindings. Returns unsubscribe. */
|
|
261
|
+
subscribe?(listener: (overrides: BindingOverrides) => void): () => void;
|
|
262
|
+
/** Optional: stored entries the store could not use (surfaced by `registry.rejectedBindings()`). */
|
|
263
|
+
rejected?(): RejectedBinding[];
|
|
264
|
+
}
|
|
265
|
+
export interface BindingInfo {
|
|
266
|
+
id: string;
|
|
267
|
+
description: string;
|
|
268
|
+
context: string;
|
|
269
|
+
group?: string;
|
|
270
|
+
/** Canonical default combos. */
|
|
271
|
+
defaults: string[];
|
|
272
|
+
/** Canonical effective combos; `[]` when unbound. */
|
|
273
|
+
current: string[];
|
|
274
|
+
isCustom: boolean;
|
|
275
|
+
rebindable: boolean;
|
|
276
|
+
}
|
|
277
|
+
export type ShortcutConflictSeverity = 'error' | 'warning' | 'info';
|
|
278
|
+
export interface ShortcutConflict {
|
|
279
|
+
/** Canonical combo, as passed in. */
|
|
280
|
+
combo: string;
|
|
281
|
+
/** The other definition's id (absent for fixed shortcuts and 'reserved'). */
|
|
282
|
+
id?: string;
|
|
283
|
+
/** The other definition's description, or the reserved combo's reason. */
|
|
284
|
+
description: string;
|
|
285
|
+
/** The other definition's context (`'browser'` for 'reserved'). */
|
|
286
|
+
context: string;
|
|
287
|
+
/**
|
|
288
|
+
* - `same-context`: both live in one context, so the older one is dead → error
|
|
289
|
+
* - `shadows`: the candidate's context sits above the other's; it wins while pushed → warning
|
|
290
|
+
* - `shadowed-by`: the other's context sits above the candidate's → warning
|
|
291
|
+
* - `modal-blocked`: the upper of the two contexts is modal, so they never compete → info
|
|
292
|
+
* - `reserved`: the browser/OS owns the combo → error (`block`) or warning (`warn`)
|
|
293
|
+
*/
|
|
294
|
+
kind: 'same-context' | 'shadows' | 'shadowed-by' | 'modal-blocked' | 'reserved';
|
|
295
|
+
severity: ShortcutConflictSeverity;
|
|
296
|
+
/** `allConflicts()` only: the candidate side of the pair (`findConflicts` callers already know it). */
|
|
297
|
+
source?: {
|
|
298
|
+
id?: string;
|
|
299
|
+
description: string;
|
|
300
|
+
context: string;
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
export interface FindConflictsTarget {
|
|
304
|
+
/** The id being (re)bound — it never conflicts with itself. Its contexts are used when `context` is absent. */
|
|
305
|
+
id?: string;
|
|
306
|
+
/** Context of the candidate. Default: the id's registered/declared contexts, else `'global'`. */
|
|
307
|
+
context?: string;
|
|
308
|
+
}
|
|
309
|
+
export interface AllConflictsOptions {
|
|
310
|
+
/** Drop conflicts below this severity. Default `'info'` (everything). */
|
|
311
|
+
minSeverity?: ShortcutConflictSeverity;
|
|
312
|
+
}
|
|
313
|
+
export type RebindResult = {
|
|
314
|
+
ok: true;
|
|
315
|
+
binding: BindingInfo;
|
|
316
|
+
displaced: string[];
|
|
317
|
+
/** Non-blocking conflicts the new binding has (shadowing, modal, reserved warnings). */
|
|
318
|
+
conflicts: ShortcutConflict[];
|
|
319
|
+
} | {
|
|
320
|
+
ok: false;
|
|
321
|
+
error: string;
|
|
322
|
+
conflicts: ShortcutConflict[];
|
|
323
|
+
};
|
|
324
|
+
export interface RebindOptions {
|
|
325
|
+
/**
|
|
326
|
+
* What to do when the new combo collides with an error-severity conflict.
|
|
327
|
+
* `'reject'` (default) fails with the conflicts; `'swap'` takes the combo
|
|
328
|
+
* away from the other id(s), leaving them with what remains; `'allow'`
|
|
329
|
+
* keeps both.
|
|
330
|
+
*/
|
|
331
|
+
onConflict?: 'reject' | 'swap' | 'allow';
|
|
332
|
+
}
|
|
333
|
+
/** A stored binding that could not be used. `id` is `'*'` for a whole unreadable blob. */
|
|
334
|
+
export interface RejectedBinding {
|
|
335
|
+
id: string;
|
|
336
|
+
/** The value exactly as stored (a combo string, a non-array value, or the raw blob). */
|
|
337
|
+
raw: unknown;
|
|
338
|
+
reason: string;
|
|
339
|
+
}
|
|
340
|
+
/** A declaration is a definition without an action — catalogue only. */
|
|
341
|
+
export type ShortcutDeclaration = Omit<ShortcutDefinition, 'action'>;
|
|
342
|
+
/**
|
|
343
|
+
* Minimal event-target shape `attach()` needs (window, document, an element).
|
|
344
|
+
* `attach()` listens for `keydown`, `keyup` and `blur`.
|
|
345
|
+
*/
|
|
107
346
|
export interface ShortcutEventTarget {
|
|
108
|
-
addEventListener(type: 'keydown', listener: (e: KeyboardEvent) => void): void;
|
|
109
|
-
removeEventListener(type: 'keydown', listener: (e: KeyboardEvent) => void): void;
|
|
347
|
+
addEventListener(type: 'keydown' | 'keyup' | 'blur', listener: (e: KeyboardEvent) => void): void;
|
|
348
|
+
removeEventListener(type: 'keydown' | 'keyup' | 'blur', listener: (e: KeyboardEvent) => void): void;
|
|
110
349
|
}
|
|
111
350
|
export interface ShortcutRegistry {
|
|
112
351
|
/** Register one or many shortcuts. Returns an unregister function. */
|
|
@@ -115,19 +354,65 @@ export interface ShortcutRegistry {
|
|
|
115
354
|
pushContext(name: string, options?: PushContextOptions): () => void;
|
|
116
355
|
/** Context names that can currently fire, top of stack first. */
|
|
117
356
|
activeContexts(): string[];
|
|
118
|
-
/** Listen for keydown on `target` (default `window`). Returns a detach function. */
|
|
357
|
+
/** Listen for keydown, keyup and blur on `target` (default `window`). Returns a detach function. */
|
|
119
358
|
attach(target?: ShortcutEventTarget): () => void;
|
|
120
|
-
/** Dispatch an event by hand. Returns true when a shortcut fired. */
|
|
359
|
+
/** Dispatch an event by hand. Returns true when a shortcut (or raw handler) fired. */
|
|
121
360
|
handleKeydown(event: KeyboardEvent): boolean;
|
|
361
|
+
/** Dispatch a keyup by hand. Returns true when a pending `onRelease` fired. */
|
|
362
|
+
handleKeyup(event: KeyboardEvent): boolean;
|
|
363
|
+
/** What `attach()` does on blur: drop pending releases, report all modifiers released. */
|
|
364
|
+
handleBlur(): void;
|
|
365
|
+
/**
|
|
366
|
+
* Register a raw handler (4.6). Consulted after its context's combos, in
|
|
367
|
+
* the same walk position; newest first. Returns unregister.
|
|
368
|
+
*/
|
|
369
|
+
registerHandler(handler: RawShortcutHandler): () => void;
|
|
370
|
+
/** Keycap label for an id's live binding (`⌘K`, `Ctrl+K`); null when the id is unknown or unbound. */
|
|
371
|
+
formatBinding(id: string): string | null;
|
|
122
372
|
/** Shortcuts grouped for `KeyboardShortcutsOverlay`'s `sections` prop. */
|
|
123
373
|
toSections(options?: ToSectionsOptions): RegistrySection[];
|
|
124
374
|
/** Every registration, in registration order. */
|
|
125
375
|
list(): ShortcutDefinition[];
|
|
126
|
-
/** Keycap label for a shortcut on this registry's platform (`⌘K`, `Ctrl+K`). */
|
|
376
|
+
/** Keycap label for a shortcut on this registry's platform (`⌘K`, `Ctrl+K`). Uses the live binding for an id. */
|
|
127
377
|
format(shortcut: ShortcutDefinition | string): string;
|
|
128
|
-
/** Notified after every register/unregister/push/pop. Returns unsubscribe. */
|
|
378
|
+
/** Notified after every register/unregister/push/pop, binding change and store load. Returns unsubscribe. */
|
|
129
379
|
subscribe(listener: () => void): () => void;
|
|
130
380
|
readonly platform: ShortcutPlatform;
|
|
381
|
+
/** Resolves once the binding store has loaded. Before then, defaults are in effect. */
|
|
382
|
+
readonly ready: Promise<void>;
|
|
383
|
+
/** Every known id (registered now, or catalogued via `declare`), first-seen order. */
|
|
384
|
+
bindings(): BindingInfo[];
|
|
385
|
+
binding(id: string): BindingInfo | undefined;
|
|
386
|
+
/**
|
|
387
|
+
* Change a binding (`null` or `[]` unbinds). Rejected, with the conflicts,
|
|
388
|
+
* when any conflict has severity `'error'` (another shortcut in the same
|
|
389
|
+
* context owns the combo, or the browser never delivers it) — unless
|
|
390
|
+
* `onConflict` says otherwise.
|
|
391
|
+
*/
|
|
392
|
+
rebind(id: string, keys: string | string[] | null, options?: RebindOptions): RebindResult;
|
|
393
|
+
resetBinding(id: string): void;
|
|
394
|
+
resetAllBindings(): void;
|
|
395
|
+
/**
|
|
396
|
+
* Stored entries that could not be parsed (from the store and from the
|
|
397
|
+
* registry's own load), with the raw value and the reason. Each is also
|
|
398
|
+
* logged once with `console.warn`. Nothing is dropped silently.
|
|
399
|
+
*/
|
|
400
|
+
rejectedBindings(): RejectedBinding[];
|
|
401
|
+
/** Make ids known before their component mounts. Returns an undeclare function. */
|
|
402
|
+
declare(defs: ShortcutDeclaration | ShortcutDeclaration[]): () => void;
|
|
403
|
+
/**
|
|
404
|
+
* Conflicts `keys` would have if bound to `target.id` (or to a new
|
|
405
|
+
* definition in `target.context`), against every registration and
|
|
406
|
+
* declaration plus the reserved list. Unparsable combos are skipped —
|
|
407
|
+
* check them with `validateCombo` first.
|
|
408
|
+
*/
|
|
409
|
+
findConflicts(keys: string | string[], target?: FindConflictsTarget): ShortcutConflict[];
|
|
410
|
+
/**
|
|
411
|
+
* Every conflict among current registrations and declarations, each pair
|
|
412
|
+
* once (the newer definition is `source`). Run it with
|
|
413
|
+
* `{ minSeverity: 'error' }` in a test over an app's catalogue.
|
|
414
|
+
*/
|
|
415
|
+
allConflicts(options?: AllConflictsOptions): ShortcutConflict[];
|
|
131
416
|
}
|
|
132
417
|
/** The sidebar-toggle convention. Ctrl+B is reserved by Chrome (bookmarks bar). */
|
|
133
418
|
export declare const SIDEBAR_TOGGLE_KEY = "mod+\\";
|
|
@@ -142,10 +427,46 @@ interface ParsedCombo {
|
|
|
142
427
|
export declare function detectPlatform(): ShortcutPlatform;
|
|
143
428
|
/** Parse `'mod+shift+k'` (plus any extra modifiers) into a normalized combo. */
|
|
144
429
|
export declare function parseCombo(key: string, extra?: ShortcutModifier | ShortcutModifier[]): ParsedCombo;
|
|
430
|
+
/**
|
|
431
|
+
* Canonical, order-stable form used for storage and equality:
|
|
432
|
+
* `"alt+shift+s"`, `"mod+k"`, `"ctrl+\`"`, `"space"`, `"mod++"`. Modifier
|
|
433
|
+
* order is mod, meta, ctrl, alt, shift. `mod` is never introduced: a stored
|
|
434
|
+
* `Ctrl+K` stays `ctrl+k`. Throws on an unknown modifier (see `validateCombo`).
|
|
435
|
+
*/
|
|
436
|
+
export declare function normalizeCombo(key: string, extra?: ShortcutModifier | ShortcutModifier[]): string;
|
|
437
|
+
/**
|
|
438
|
+
* Canonical combo for a live keydown (a settings "press the new shortcut"
|
|
439
|
+
* recorder). Null while only modifiers are down, or when the key can't be
|
|
440
|
+
* identified. Ctrl/Meta are reported literally (never `mod`). Uses the
|
|
441
|
+
* physical key when macOS Option (or a dead key / non-ASCII layout) hides it.
|
|
442
|
+
*/
|
|
443
|
+
export declare function comboFromEvent(event: KeyboardEvent, platform?: ShortcutPlatform): string | null;
|
|
444
|
+
/**
|
|
445
|
+
* Structural validation for a user-entered binding. Null means valid,
|
|
446
|
+
* otherwise a human-readable reason. `requireModifier` demands Ctrl, Alt,
|
|
447
|
+
* Meta or mod (Shift alone doesn't count) — the IDE's rule for global ids.
|
|
448
|
+
*/
|
|
449
|
+
export declare function validateCombo(key: string, options?: {
|
|
450
|
+
requireModifier?: boolean;
|
|
451
|
+
}): string | null;
|
|
145
452
|
/** True when keystrokes on `target` are text entry (so bare-key shortcuts must not fire). */
|
|
146
453
|
export declare function isTypingTarget(target: EventTarget | null | undefined): boolean;
|
|
147
|
-
/** Keycap label: `⌘⇧K` on macOS, `Ctrl+Shift+K` elsewhere. */
|
|
148
|
-
export declare function formatShortcut(shortcut: ShortcutDefinition | string, platform?: ShortcutPlatform): string;
|
|
454
|
+
/** Keycap label: `⌘⇧K` on macOS, `Ctrl+Shift+K` elsewhere. Several keys join with `' / '`. */
|
|
455
|
+
export declare function formatShortcut(shortcut: ShortcutDefinition | ShortcutDeclaration | string, platform?: ShortcutPlatform): string;
|
|
456
|
+
/**
|
|
457
|
+
* Versioned localStorage `BindingStore`: `{ v: 1, bindings, rejected? }`.
|
|
458
|
+
* Tolerates corrupt JSON, a foreign shape and unavailable storage (private
|
|
459
|
+
* mode, SSR) — all read as "no overrides". `migrate` runs only when
|
|
460
|
+
* `storageKey` is absent, and its result (even an empty one) is written so
|
|
461
|
+
* it runs once. Entries it can't parse (from storage or from `migrate`) are
|
|
462
|
+
* warned once, exposed via `rejected()`, and kept in the stored `rejected`
|
|
463
|
+
* list so a later save doesn't lose them.
|
|
464
|
+
* `syncTabs` (default true) forwards other tabs' writes via `storage` events.
|
|
465
|
+
*/
|
|
466
|
+
export declare function localStorageBindingStore(storageKey: string, options?: {
|
|
467
|
+
migrate?: () => BindingOverrides | null;
|
|
468
|
+
syncTabs?: boolean;
|
|
469
|
+
}): BindingStore;
|
|
149
470
|
export declare function createShortcutRegistry(options?: ShortcutRegistryOptions): ShortcutRegistry;
|
|
150
471
|
/** Lazily-created app-wide registry, for apps that want one without threading it through props. */
|
|
151
472
|
export declare function getShortcutRegistry(): ShortcutRegistry;
|