From e0d0582517bd08e399853624668655b34f62b533 Mon Sep 17 00:00:00 2001 From: Naman Date: Sun, 20 Sep 2026 00:58:25 +0200 Subject: [PATCH] chore(core): type the 'help' event, test the shortcuts overlay Follow-up to #15: add 'help' to EditorEvent, fix the indentation of the new _keyDown branch, list ? in the README key table, and cover the overlay's open/close/destroy paths. Co-Authored-By: Claude Fable 5.1 --- README.md | 1 + packages/core/src/editor.js | 3 ++- packages/core/test/editor.test.js | 37 +++++++++++++++++++++++++++++++ packages/core/types/index.d.ts | 2 +- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 107c89d..d6c6d7a 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,7 @@ socket.onmessage = (e) => store.applyDiff(JSON.parse(e.data), 'remote') | `⌘+` / `⌘−` | Zoom in / out | | `⌫` / `⇧⌘⌫` | Delete selection / clear the board (undoable) | | `Enter` / `Esc` | Edit text / done | +| `?` | Show this list on the board | ## Repository diff --git a/packages/core/src/editor.js b/packages/core/src/editor.js index e0f78cf..31e07db 100644 --- a/packages/core/src/editor.js +++ b/packages/core/src/editor.js @@ -1262,7 +1262,8 @@ export class Editor { else this.setTool('select') return } - if (k === '?') { e.preventDefault(); this.emit('help'); return } + // the UI layer listens for this and toggles the shortcuts overlay + if (k === '?') { e.preventDefault(); this.emit('help'); return } // wipe the board — two modifiers deep, and undoable like any other edit if (meta && e.shiftKey && (k === 'delete' || k === 'backspace')) { e.preventDefault() diff --git a/packages/core/test/editor.test.js b/packages/core/test/editor.test.js index a8b3872..138ec9a 100644 --- a/packages/core/test/editor.test.js +++ b/packages/core/test/editor.test.js @@ -652,3 +652,40 @@ describe('createQuickdraw UI', () => { c2.remove() }) }) + +describe('keyboard help overlay', () => { + const press = (board, key) => + board.editor._keyDown({ key, shiftKey: true, metaKey: false, ctrlKey: false, preventDefault() {} }) + + it('? toggles the overlay, Esc closes it, destroy tears it down', () => { + const c2 = document.createElement('div') + document.body.appendChild(c2) + const board = createQuickdraw({ container: c2 }) + const open = () => !!c2.querySelector('.qd-help-backdrop') + + press(board, '?') + expect(open()).toBe(true) + expect(c2.querySelectorAll('.qd-help-row').length).toBeGreaterThan(20) + press(board, '?') + expect(open()).toBe(false) + + press(board, '?') + document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' })) + expect(open()).toBe(false) + + press(board, '?') + board.destroy() + expect(document.querySelector('.qd-help-backdrop')).toBe(null) + c2.remove() + }) + + it('stays quiet on a readonly board', () => { + const c2 = document.createElement('div') + document.body.appendChild(c2) + const board = createQuickdraw({ container: c2, readonly: true }) + press(board, '?') + expect(c2.querySelector('.qd-help-backdrop')).toBe(null) + board.destroy() + c2.remove() + }) +}) diff --git a/packages/core/types/index.d.ts b/packages/core/types/index.d.ts index bd5cbe2..7381c06 100644 --- a/packages/core/types/index.d.ts +++ b/packages/core/types/index.d.ts @@ -194,7 +194,7 @@ export interface EditorOptions { export type EditorEvent = | 'change' | 'history' | 'camera' | 'tool' | 'styles' | 'selection' - | 'theme' | 'grid' | 'edit' | 'scribbles' | 'penmode' + | 'theme' | 'grid' | 'edit' | 'scribbles' | 'penmode' | 'help' /** * The editor: camera, tools, selection, input and rendering over a Store.