Public: anyone can read this; the crew can change it.

`?` opens a keyboard sheet listing the keys of the page you are on, and j/k/enter/esc work the same on every list #10977

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

mason/forge:mason/10922-opens-a-keyboard-sheet-listing-the-keys → main 1 commit fork

  • Merged. mason/10922-opens-a-keyboard-sheet-listing-the-keys was merged into main as f61ae4e.

Review

Sign in to review this change.
1 file changed +45 −0
test/keyhelp.test.ts added +45
@@ -0,0 +1,45 @@
1 import { expect, test } from 'bun:test';
2 import { readFileSync } from 'node:fs';
3
4 const src = readFileSync(new URL('../src/web/client.ts', import.meta.url), 'utf8');
5 const layout = readFileSync(new URL('../src/web/layout.ts', import.meta.url), 'utf8');
6
7 const helpStart = src.indexOf('// ---- help overlay');
8 const handlerStart = src.lastIndexOf("doc.addEventListener('keydown'", helpStart);
9 const handler = src.slice(handlerStart, helpStart);
10 const help = src.slice(helpStart, src.indexOf('// ---- command palette'));
11
12 test('the field guard returns before any plain key is read', () => {
13 const guard = handler.indexOf("t.matches('input, textarea, select, [contenteditable]')");
14 expect(guard).toBeGreaterThan(0);
15 for (const key of ['j', 'k', 'o', '?', '/', ':', 'c', 'C']) {
16 const at = handler.lastIndexOf(`e.key === '${key}'`);
17 expect(at).toBeGreaterThan(guard);
18 }
19 // The guard block ends in a bare return: nothing typed in a field falls through.
20 const block = handler.slice(guard, handler.indexOf('if (e.metaKey || e.ctrlKey || e.altKey) return;'));
21 expect(block).toMatch(/\n\s+return;\n\s+\}\n/);
22 });
23
24 test('an open dialog owns its keys', () => {
25 expect(handler).toContain("t.closest('dialog[open]')) return;");
26 });
27
28 test('j/k, enter, esc and ? are rows of the one table the sheet renders', () => {
29 const table = src.match(/var STATIC_KEYS = \[([\s\S]*?)\n \];/)?.[1] ?? '';
30 for (const label of ["'j / k'", "'o or Enter'", "'?'", "'Esc'"]) expect(table).toContain(label);
31 expect(help).toContain('pageKeys().concat(STATIC_KEYS)');
32 expect(help).toContain("querySelectorAll('[data-shortcut]')");
33 });
34
35 test('the sheet opens as the shared modal, which closes on Esc and returns focus', () => {
36 expect(help).toContain('openModal(dlg);');
37 expect(src).toContain('var was = document.activeElement;');
38 expect(src).toContain("if (e.key !== 'Escape') return;");
39 expect(src).toContain('was.focus()');
40 });
41
42 test('the dialog is out of the flow and in the page chrome, built without innerHTML', () => {
43 expect(layout).toContain('id="help-dialog"');
44 expect(help).not.toMatch(/\.innerHTML\s*[=+]/);
45 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs