import { useEffect, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { useUIStore } from '@/stores/ui'; /** * FE-COMP-022: Global keyboard shortcuts hook for common actions */ export interface GlobalKeyboardShortcutsOptions { enabled?: boolean; preventDefault?: boolean; onHelpOpen?: () => void; } export function useGlobalKeyboardShortcuts( options: GlobalKeyboardShortcutsOptions = {}, ) { const { enabled = true, preventDefault = true, onHelpOpen } = options; const navigate = useNavigate(); const { setSidebarOpen, sidebarOpen } = useUIStore(); const handleKeyDown = useCallback( (e: KeyboardEvent) => { if (!enabled) return; // Ignorer si l'utilisateur est en train de taper dans un input/textarea/contenteditable const target = e.target as HTMLElement; if ( target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable === true || target.getAttribute('role') === 'textbox') ) { // Permettre Ctrl+K même dans les inputs pour la recherche if (e.key === 'k' && (e.ctrlKey || e.metaKey)) { // Ctrl+K ou Cmd+K : Focus sur la recherche if (preventDefault) { e.preventDefault(); } const searchInput = document.querySelector( 'input[type="search"], input[placeholder*="search" i], input[placeholder*="rechercher" i]', ) as HTMLInputElement; if (searchInput) { searchInput.focus(); searchInput.select(); } else { // Sinon, naviguer vers la page de recherche navigate('/search'); } return; } return; } // Ctrl+K ou Cmd+K : Focus sur la recherche ou naviguer vers /search if ((e.ctrlKey || e.metaKey) && e.key === 'k') { if (preventDefault) { e.preventDefault(); } const searchInput = document.querySelector( 'input[type="search"], input[placeholder*="search" i], input[placeholder*="rechercher" i]', ) as HTMLInputElement; if (searchInput) { searchInput.focus(); searchInput.select(); } else { navigate('/search'); } return; } // Ctrl+N ou Cmd+N : Nouveau message/chat if ((e.ctrlKey || e.metaKey) && e.key === 'n') { if (preventDefault) { e.preventDefault(); } navigate('/chat'); return; } // Ctrl+B ou Cmd+B : Toggle sidebar if ((e.ctrlKey || e.metaKey) && e.key === 'b') { if (preventDefault) { e.preventDefault(); } setSidebarOpen(!sidebarOpen); return; } // Escape : Fermer les modals/dropdowns ou retourner en arrière if (e.key === 'Escape') { // Fermer les dropdowns ouverts const openDropdowns = document.querySelectorAll( '[role="menu"][aria-expanded="true"]', ); openDropdowns.forEach((dropdown) => { const button = dropdown.previousElementSibling as HTMLElement; if (button) { button.click(); } }); return; } // ? : Afficher l'aide des raccourcis if (e.key === '?' && !e.ctrlKey && !e.metaKey && !e.shiftKey) { if (preventDefault) { e.preventDefault(); } if (onHelpOpen) { onHelpOpen(); } return; } }, [ enabled, preventDefault, navigate, setSidebarOpen, sidebarOpen, onHelpOpen, ], ); useEffect(() => { if (!enabled) return; window.addEventListener('keydown', handleKeyDown); return () => { window.removeEventListener('keydown', handleKeyDown); }; }, [enabled, handleKeyDown]); }