From 0dcc96dee6c4f1a8d843699f4ed2e1db3c1871fc Mon Sep 17 00:00:00 2001 From: jlightner Date: Thu, 26 Mar 2026 05:41:41 +0000 Subject: [PATCH] =?UTF-8?q?test:=20Add=20canvas=20keyboard=20shortcuts=20(?= =?UTF-8?q?undo/redo/delete/select-all/desele=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - "app/src/views/DesignCanvas.tsx" GSD-Task: S02/T04 --- app/src/views/DesignCanvas.tsx | 55 +++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/app/src/views/DesignCanvas.tsx b/app/src/views/DesignCanvas.tsx index 26dbfc7..feed48a 100644 --- a/app/src/views/DesignCanvas.tsx +++ b/app/src/views/DesignCanvas.tsx @@ -33,7 +33,7 @@ export default function DesignCanvas({ const { state, addObject, - removeObject: _removeObject, + removeObject, updateObject, selectObjects, deselectAll, @@ -170,6 +170,59 @@ export default function DesignCanvas({ setZoomLevel(1); }, []); + // -- Keyboard shortcuts --------------------------------------------------- + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + // Don't fire shortcuts when typing in an input/textarea + const tag = (document.activeElement?.tagName ?? '').toLowerCase(); + if (tag === 'input' || tag === 'textarea' || tag === 'select') return; + + const ctrl = e.ctrlKey || e.metaKey; + + if (ctrl && e.shiftKey && e.key.toLowerCase() === 'z') { + e.preventDefault(); + redo(); + return; + } + + if (ctrl && e.key.toLowerCase() === 'z') { + e.preventDefault(); + undo(); + return; + } + + if (ctrl && e.key.toLowerCase() === 'y') { + e.preventDefault(); + redo(); + return; + } + + if (ctrl && e.key.toLowerCase() === 'a') { + e.preventDefault(); + selectObjects(state.objects.map((o) => o.id)); + return; + } + + if (e.key === 'Delete' || e.key === 'Backspace') { + e.preventDefault(); + for (const id of state.selectedIds) { + removeObject(id); + } + return; + } + + if (e.key === 'Escape') { + e.preventDefault(); + deselectAll(); + return; + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [undo, redo, removeObject, selectObjects, deselectAll, state.objects, state.selectedIds]); + // -- Selected object for properties panel --------------------------------- const selectedObject = useMemo(() => {