@remit/web-client 0.0.115 → 0.0.117
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/package.json +1 -1
- package/src/components/layout/MailTopBar.tsx +1 -2
- package/src/components/mail/FlaggedList.tsx +0 -1
- package/src/components/mail/MessageList.tsx +0 -1
- package/src/components/mail/MessageToolbar.tsx +1 -1
- package/src/components/mail/ThreadListInteraction.tsx +1 -2
- package/src/components/ui/KeyboardShortcutsModal.tsx +2 -3
- package/src/hooks/useTriageLayer.ts +1 -4
- package/src/hooks/useListCursor.test.ts +0 -273
- package/src/hooks/useListCursor.ts +0 -259
- package/src/hooks/useTriageKeyboard.ts +0 -108
- package/src/lib/keymap-dispatch.test.ts +0 -255
- package/src/lib/keymap-dispatch.ts +0 -244
- package/src/lib/keymap.test.ts +0 -68
- package/src/lib/keymap.ts +0 -210
package/src/lib/keymap.ts
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Single source of truth for the global keyboard triage layer (#429).
|
|
3
|
-
*
|
|
4
|
-
* Every shortcut the app responds to is declared here once. The help overlay
|
|
5
|
-
* (`KeyboardShortcutsModal`), the list footer hints and the toolbar tooltips
|
|
6
|
-
* all read from this module so the displayed bindings can never drift from the
|
|
7
|
-
* keys the dispatcher actually routes. The spec lives in
|
|
8
|
-
* `doc/design/flows/04-triage.md`.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/** A logical action a key (or key sequence) maps to. */
|
|
12
|
-
export type TriageAction =
|
|
13
|
-
// list navigation / focus model
|
|
14
|
-
| "focusNext"
|
|
15
|
-
| "focusPrevious"
|
|
16
|
-
| "focusFirst"
|
|
17
|
-
| "focusLast"
|
|
18
|
-
| "openFocused"
|
|
19
|
-
| "back"
|
|
20
|
-
// selection
|
|
21
|
-
| "toggleSelect"
|
|
22
|
-
| "extendSelectDown"
|
|
23
|
-
| "extendSelectUp"
|
|
24
|
-
| "selectAll"
|
|
25
|
-
// message verbs (focused row / selection)
|
|
26
|
-
| "reply"
|
|
27
|
-
| "replyAll"
|
|
28
|
-
| "forward"
|
|
29
|
-
| "delete"
|
|
30
|
-
| "toggleStar"
|
|
31
|
-
| "toggleRead"
|
|
32
|
-
// sender verbs
|
|
33
|
-
| "muteSender"
|
|
34
|
-
| "blockSender"
|
|
35
|
-
| "vipSender"
|
|
36
|
-
| "markJunk"
|
|
37
|
-
// view
|
|
38
|
-
| "toggleIntelligence"
|
|
39
|
-
| "toggleDensity"
|
|
40
|
-
// global
|
|
41
|
-
| "focusSearch"
|
|
42
|
-
| "compose"
|
|
43
|
-
| "help"
|
|
44
|
-
// go-to sequences (g then …)
|
|
45
|
-
| "goBrief"
|
|
46
|
-
| "goInbox"
|
|
47
|
-
| "goSent"
|
|
48
|
-
| "goFlagged"
|
|
49
|
-
| "goSettings";
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* One displayed binding row in the help overlay. `keys` is the human-readable
|
|
53
|
-
* sequence (e.g. ["g", "b"] or ["⌘", "N"]); `display` overrides the rendered
|
|
54
|
-
* label when a single token reads better (e.g. "Esc", "↵").
|
|
55
|
-
*/
|
|
56
|
-
export interface KeyHint {
|
|
57
|
-
action: TriageAction;
|
|
58
|
-
/** Tokens rendered as individual <Kbd> chips, in order. */
|
|
59
|
-
keys: string[];
|
|
60
|
-
description: string;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface KeyHintGroup {
|
|
64
|
-
title: string;
|
|
65
|
-
hints: KeyHint[];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* The full key map, grouped by area, exactly as it appears in the `?` overlay.
|
|
70
|
-
* Order is intentional (matches 04-triage.md reading order).
|
|
71
|
-
*/
|
|
72
|
-
export const KEY_HINT_GROUPS: KeyHintGroup[] = [
|
|
73
|
-
{
|
|
74
|
-
title: "Navigation",
|
|
75
|
-
hints: [
|
|
76
|
-
{ action: "focusNext", keys: ["j"], description: "Focus next message" },
|
|
77
|
-
{
|
|
78
|
-
action: "focusPrevious",
|
|
79
|
-
keys: ["k"],
|
|
80
|
-
description: "Focus previous message",
|
|
81
|
-
},
|
|
82
|
-
{ action: "focusNext", keys: ["↓"], description: "Focus next message" },
|
|
83
|
-
{
|
|
84
|
-
action: "focusPrevious",
|
|
85
|
-
keys: ["↑"],
|
|
86
|
-
description: "Focus previous message",
|
|
87
|
-
},
|
|
88
|
-
{ action: "focusFirst", keys: ["Home"], description: "Focus first" },
|
|
89
|
-
{ action: "focusLast", keys: ["End"], description: "Focus last" },
|
|
90
|
-
{
|
|
91
|
-
action: "openFocused",
|
|
92
|
-
keys: ["Enter"],
|
|
93
|
-
description: "Open focused thread",
|
|
94
|
-
},
|
|
95
|
-
{ action: "back", keys: ["Esc"], description: "Back / close overlay" },
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
title: "Selection",
|
|
100
|
-
hints: [
|
|
101
|
-
{ action: "toggleSelect", keys: ["x"], description: "Toggle select" },
|
|
102
|
-
{ action: "toggleSelect", keys: ["Space"], description: "Toggle select" },
|
|
103
|
-
{
|
|
104
|
-
action: "extendSelectDown",
|
|
105
|
-
keys: ["Shift", "j"],
|
|
106
|
-
description: "Extend selection down",
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
action: "extendSelectUp",
|
|
110
|
-
keys: ["Shift", "k"],
|
|
111
|
-
description: "Extend selection up",
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
action: "extendSelectDown",
|
|
115
|
-
keys: ["Shift", "↓"],
|
|
116
|
-
description: "Extend selection down",
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
action: "extendSelectUp",
|
|
120
|
-
keys: ["Shift", "↑"],
|
|
121
|
-
description: "Extend selection up",
|
|
122
|
-
},
|
|
123
|
-
{ action: "selectAll", keys: ["⌘", "A"], description: "Select all" },
|
|
124
|
-
],
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
title: "Actions",
|
|
128
|
-
hints: [
|
|
129
|
-
{ action: "reply", keys: ["r"], description: "Reply" },
|
|
130
|
-
{ action: "replyAll", keys: ["a"], description: "Reply all" },
|
|
131
|
-
{ action: "forward", keys: ["f"], description: "Forward" },
|
|
132
|
-
{ action: "delete", keys: ["#"], description: "Delete" },
|
|
133
|
-
{ action: "toggleStar", keys: ["s"], description: "Star / unstar" },
|
|
134
|
-
{
|
|
135
|
-
action: "toggleRead",
|
|
136
|
-
keys: ["u"],
|
|
137
|
-
description: "Toggle read / unread",
|
|
138
|
-
},
|
|
139
|
-
],
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
title: "Sender",
|
|
143
|
-
hints: [
|
|
144
|
-
{ action: "muteSender", keys: ["m"], description: "Mute sender" },
|
|
145
|
-
{ action: "blockSender", keys: ["b"], description: "Block sender" },
|
|
146
|
-
{ action: "vipSender", keys: ["v"], description: "VIP sender" },
|
|
147
|
-
{ action: "markJunk", keys: ["!"], description: "Mark junk" },
|
|
148
|
-
],
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
title: "Go to",
|
|
152
|
-
hints: [
|
|
153
|
-
{ action: "goBrief", keys: ["g", "b"], description: "Daily brief" },
|
|
154
|
-
{ action: "goInbox", keys: ["g", "i"], description: "Inbox" },
|
|
155
|
-
{ action: "goSent", keys: ["g", "s"], description: "Sent" },
|
|
156
|
-
{ action: "goFlagged", keys: ["g", "f"], description: "Starred" },
|
|
157
|
-
{ action: "goSettings", keys: ["g", ","], description: "Settings" },
|
|
158
|
-
],
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
title: "View & global",
|
|
162
|
-
hints: [
|
|
163
|
-
{
|
|
164
|
-
action: "toggleIntelligence",
|
|
165
|
-
keys: ["i"],
|
|
166
|
-
description: "Toggle intelligence",
|
|
167
|
-
},
|
|
168
|
-
{ action: "toggleDensity", keys: ["d"], description: "Toggle density" },
|
|
169
|
-
{ action: "focusSearch", keys: ["/"], description: "Focus search" },
|
|
170
|
-
{ action: "compose", keys: ["c"], description: "Compose" },
|
|
171
|
-
{ action: "compose", keys: ["⌘", "N"], description: "Compose" },
|
|
172
|
-
{ action: "help", keys: ["?"], description: "Shortcut help" },
|
|
173
|
-
],
|
|
174
|
-
},
|
|
175
|
-
];
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Look up the displayed key tokens for an action (first matching hint). Used by
|
|
179
|
-
* toolbar tooltips so a single declaration drives both the overlay and the
|
|
180
|
-
* button titles. Returns `undefined` for actions with no hint.
|
|
181
|
-
*/
|
|
182
|
-
export function keysForAction(action: TriageAction): string[] | undefined {
|
|
183
|
-
for (const group of KEY_HINT_GROUPS) {
|
|
184
|
-
const hint = group.hints.find((h) => h.action === action);
|
|
185
|
-
if (hint) return hint.keys;
|
|
186
|
-
}
|
|
187
|
-
return undefined;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Render an action's binding as it reads to a user, e.g. "r" or "g then b".
|
|
192
|
-
* Returns "" when the action has no hint.
|
|
193
|
-
*/
|
|
194
|
-
export function shortcutHintForAction(action: TriageAction): string {
|
|
195
|
-
const keys = keysForAction(action);
|
|
196
|
-
if (!keys || keys.length === 0) return "";
|
|
197
|
-
if (keys.length === 1) return keys[0] ?? "";
|
|
198
|
-
// Sequence (go-to) keys read as "g then b"; modifier combos as "⌘N".
|
|
199
|
-
if (keys[0] === "g") return keys.join(" then ");
|
|
200
|
-
return keys.join("");
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Render an action's binding as a compact tooltip suffix, e.g. "(r)" or
|
|
205
|
-
* "(g then b)". Returns "" when the action has no hint.
|
|
206
|
-
*/
|
|
207
|
-
export function tooltipForAction(action: TriageAction): string {
|
|
208
|
-
const hint = shortcutHintForAction(action);
|
|
209
|
-
return hint === "" ? "" : `(${hint})`;
|
|
210
|
-
}
|