# All files / src/hooks useAppKeyboard.ts

95.45% Statements 42/44
96.55% Branches 28/29
84.61% Functions 11/13
94.44% Lines 34/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98

    2x

    2x
    2x

    2x

    17x

    17x
    15x
    15x
    7x
    7x
    7x

    10x
    10x
    9x
    9x
    8x
    7x
    7x
    7x

    49x
    196x
    2x
    2x

    49x

    1x

    49x

    19x
    2x
    2x
    2x

    17x
    10x

    49x
    49x

     import { useEffect } from 'react'
    import type { ViewMode } from './useViewMode'

    interface KeyboardActions {
      onQuickOpen: () => void
      onCommandPalette: () => void
      onSearch: () => void
      onCreateNote: () => void
      onSave: () => void
      onOpenSettings: () => void
      onTrashNote: (path: string) => void
      onArchiveNote: (path: string) => void
      onSetViewMode: (mode: ViewMode) => void
      onGoBack?: () => void
      onGoForward?: () => void
      activeTabPathRef: React.MutableRefObject<string | null>
      handleCloseTabRef: React.MutableRefObject<(path: string) => void>
    }

    type ShortcutHandler = () => void

    const TEXT_EDITING_KEYS = new Set(['Backspace', 'Delete'])

    function isTextInputFocused(): boolean {
      const tag = document.activeElement?.tagName
      return tag === 'INPUT' || tag === 'TEXTAREA'
    }

    const VIEW_MODE_KEYS: Record<string, ViewMode> = {
      '1': 'editor-only',
      '2': 'editor-list',
      '3': 'all',
    }

    function isCmdOnly(e: KeyboardEvent): boolean {
      return (e.metaKey || e.ctrlKey) && !e.altKey
    }

    function handleViewModeKey(e: KeyboardEvent, onSetViewMode: (m: ViewMode) => void): boolean {
      if (!isCmdOnly(e)) return false
      const mode = VIEW_MODE_KEYS[e.key]
      if (!mode) return false
      e.preventDefault()
      onSetViewMode(mode)
      return true
    }

    function handleCmdKey(e: KeyboardEvent, keyMap: Record<string, ShortcutHandler>): boolean {
      const mod = e.metaKey || e.ctrlKey
      if (!mod) return false
      const handler = keyMap[e.key]
      if (!handler) return false
      if (TEXT_EDITING_KEYS.has(e.key) && isTextInputFocused()) return false
      e.preventDefault()
      handler()
      return true
    }

    export function useAppKeyboard({
      onQuickOpen, onCommandPalette, onSearch, onCreateNote, onSave, onOpenSettings, onTrashNote, onArchiveNote,
      onSetViewMode, onGoBack, onGoForward, activeTabPathRef, handleCloseTabRef,
    }: KeyboardActions) {
      useEffect(() => {
        const withActiveTab = (fn: (path: string) => void): ShortcutHandler => () => {
          const path = activeTabPathRef.current
          Eif (path) fn(path)
        }

        const cmdKeyMap: Record<string, ShortcutHandler> = {
          k: onCommandPalette,
          p: onQuickOpen,
          n: onCreateNote,
          s: onSave,
          ',': onOpenSettings,
          e: withActiveTab(onArchiveNote),
          w: withActiveTab((path) => handleCloseTabRef.current(path)),
          Backspace: withActiveTab(onTrashNote),
          Delete: withActiveTab(onTrashNote),
          '[': () => onGoBack?.(),
          ']': () => onGoForward?.(),
        }

        const handleKeyDown = (e: KeyboardEvent) => {
          // Cmd+Shift+F: full-text search (distinct from Cmd+F browser find)
          if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === 'f') {
            e.preventDefault()
            onSearch()
            return
          }
          if (!handleViewModeKey(e, onSetViewMode)) {
            handleCmdKey(e, cmdKeyMap)
          }
        }
        window.addEventListener('keydown', handleKeyDown)
        return () => window.removeEventListener('keydown', handleKeyDown)
      }, [onQuickOpen, onCommandPalette, onSearch, onCreateNote, onSave, onOpenSettings, onTrashNote, onArchiveNote, activeTabPathRef, handleCloseTabRef, onSetViewMode, onGoBack, onGoForward])
    }