Spaces:
Running
Running
| /* | |
| * useKeyboardShortcuts.ts | |
| * Purpose: Encapsulates keyboard shortcut handling for editor selection, formatting, and undo/redo actions. | |
| * Used by: GoogleSlidesEditor. | |
| * Depends on: Window keyboard events and editor mutation callbacks. | |
| */ | |
| import { useEffect } from 'react'; | |
| import type { TextElement, EditorElement } from '@/lib/editor-types'; | |
| interface UseKeyboardShortcutsParams { | |
| isEditingTextId: string | null; | |
| selectedId: string | null; | |
| currentSlideElements: EditorElement[]; | |
| currentSlideIndex: number; | |
| handleUndo: () => void; | |
| handleRedo: () => void; | |
| updateElement: (id: string, updates: Partial<EditorElement>) => void; | |
| deleteElement: (id: string) => void; | |
| setSelectedId: (id: string | null) => void; | |
| } | |
| export function useKeyboardShortcuts({ | |
| isEditingTextId, | |
| selectedId, | |
| currentSlideElements, | |
| currentSlideIndex, | |
| handleUndo, | |
| handleRedo, | |
| updateElement, | |
| deleteElement, | |
| setSelectedId, | |
| }: UseKeyboardShortcutsParams) { | |
| useEffect(() => { | |
| const onKey = (e: KeyboardEvent) => { | |
| if (isEditingTextId) return; | |
| if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) { | |
| e.preventDefault(); | |
| handleUndo(); | |
| return; | |
| } | |
| if ((e.ctrlKey || e.metaKey) && (e.key === 'y' || (e.key === 'z' && e.shiftKey))) { | |
| e.preventDefault(); | |
| handleRedo(); | |
| return; | |
| } | |
| if (selectedId && (e.ctrlKey || e.metaKey)) { | |
| const element = currentSlideElements.find(el => el.id === selectedId); | |
| if (element?.type === 'text') { | |
| const textEl = element as TextElement; | |
| if (e.key === 'b') { | |
| e.preventDefault(); | |
| updateElement(selectedId, { fontWeight: textEl.fontWeight === 'bold' ? 'normal' : 'bold' }); | |
| return; | |
| } | |
| if (e.key === 'i') { | |
| e.preventDefault(); | |
| updateElement(selectedId, { fontStyle: textEl.fontStyle === 'italic' ? 'normal' : 'italic' }); | |
| return; | |
| } | |
| if (e.key === 'u') { | |
| e.preventDefault(); | |
| updateElement(selectedId, { textDecoration: textEl.textDecoration === 'underline' ? 'none' : 'underline' }); | |
| return; | |
| } | |
| } | |
| } | |
| if (e.key === 'Delete' && selectedId) { | |
| deleteElement(selectedId); | |
| setSelectedId(null); | |
| } | |
| }; | |
| window.addEventListener('keydown', onKey); | |
| return () => window.removeEventListener('keydown', onKey); | |
| }, [selectedId, currentSlideIndex, handleUndo, handleRedo, isEditingTextId, currentSlideElements, updateElement, deleteElement, setSelectedId]); | |
| } | |