- Wrap ref assignments in useEffect to fix refs-during-render in useTabManagement, useKeyboardNavigation, and Editor - Rewrite useAppKeyboard to define keyMap inside useEffect, eliminating ref access during render - Add eslint-disable for react-hooks/set-state-in-effect on legitimate dialog reset patterns (CommitDialog, CreateNoteDialog, CreateTypeDialog, QuickOpenPalette, AIChatPanel, useVaultLoader) - Add eslint-disable for react-hooks/static-components on icon lookups (NoteItem, NoteList PinnedCard) — stateless icon components from a static map - Add eslint-disable for react-hooks/purity on Date.now() in NoteItem TrashDateLine — intentionally memoized on trashedAt - Remove unused `model` param from buildSystemPrompt (ai-chat.ts) and update callers - Fix exhaustive-deps: suppress vault object dep in App.tsx git history effect (vault object is unstable, loadGitHistory is the real dep) - Remove unused `modifiedFiles` from useNoteListData params and caller - Add missing `ref` to Sidebar useOutsideClick deps Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
48 lines
1.5 KiB
TypeScript
48 lines
1.5 KiB
TypeScript
import { useEffect } from 'react'
|
|
|
|
interface KeyboardActions {
|
|
onQuickOpen: () => void
|
|
onCreateNote: () => void
|
|
onSave: () => void
|
|
onTrashNote: (path: string) => void
|
|
onArchiveNote: (path: string) => void
|
|
activeTabPathRef: React.MutableRefObject<string | null>
|
|
handleCloseTabRef: React.MutableRefObject<(path: string) => void>
|
|
}
|
|
|
|
type ShortcutHandler = () => void
|
|
|
|
export function useAppKeyboard({
|
|
onQuickOpen, onCreateNote, onSave, onTrashNote, onArchiveNote,
|
|
activeTabPathRef, handleCloseTabRef,
|
|
}: KeyboardActions) {
|
|
useEffect(() => {
|
|
const withActiveTab = (fn: (path: string) => void): ShortcutHandler => () => {
|
|
const path = activeTabPathRef.current
|
|
if (path) fn(path)
|
|
}
|
|
|
|
const keyMap: Record<string, ShortcutHandler> = {
|
|
p: onQuickOpen,
|
|
n: onCreateNote,
|
|
s: onSave,
|
|
e: withActiveTab(onArchiveNote),
|
|
w: withActiveTab((path) => handleCloseTabRef.current(path)),
|
|
Backspace: withActiveTab(onTrashNote),
|
|
Delete: withActiveTab(onTrashNote),
|
|
}
|
|
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
const mod = e.metaKey || e.ctrlKey
|
|
if (!mod) return
|
|
const handler = keyMap[e.key]
|
|
if (handler) {
|
|
e.preventDefault()
|
|
handler()
|
|
}
|
|
}
|
|
window.addEventListener('keydown', handleKeyDown)
|
|
return () => window.removeEventListener('keydown', handleKeyDown)
|
|
}, [onQuickOpen, onCreateNote, onSave, onTrashNote, onArchiveNote, activeTabPathRef, handleCloseTabRef])
|
|
}
|