({
isActive,
onExit,
onCancel,
onExitUp,
columns,
passthroughCtrlKeys = [],
initialQuery = '',
backspaceExitsOnEmpty = true,
}: UseSearchInputOptions)
| 82 | ]) |
| 83 | |
| 84 | export function useSearchInput({ |
| 85 | isActive, |
| 86 | onExit, |
| 87 | onCancel, |
| 88 | onExitUp, |
| 89 | columns, |
| 90 | passthroughCtrlKeys = [], |
| 91 | initialQuery = '', |
| 92 | backspaceExitsOnEmpty = true, |
| 93 | }: UseSearchInputOptions): UseSearchInputReturn { |
| 94 | const { columns: terminalColumns } = useTerminalSize() |
| 95 | const effectiveColumns = columns ?? terminalColumns |
| 96 | const [query, setQueryState] = useState(initialQuery) |
| 97 | const [cursorOffset, setCursorOffset] = useState(initialQuery.length) |
| 98 | |
| 99 | const setQuery = useCallback((q: string) => { |
| 100 | setQueryState(q) |
| 101 | setCursorOffset(q.length) |
| 102 | }, []) |
| 103 | |
| 104 | const handleKeyDown = (e: KeyboardEvent): void => { |
| 105 | if (!isActive) return |
| 106 | |
| 107 | const cursor = Cursor.fromText(query, effectiveColumns, cursorOffset) |
| 108 | |
| 109 | // Check passthrough ctrl keys |
| 110 | if (e.ctrl && passthroughCtrlKeys.includes(e.key.toLowerCase())) { |
| 111 | return |
| 112 | } |
| 113 | |
| 114 | // Reset kill accumulation for non-kill keys |
| 115 | if (!isKillKey(e)) { |
| 116 | resetKillAccumulation() |
| 117 | } |
| 118 | |
| 119 | // Reset yank state for non-yank keys |
| 120 | if (!isYankKey(e)) { |
| 121 | resetYankState() |
| 122 | } |
| 123 | |
| 124 | // Exit conditions |
| 125 | if (e.key === 'return' || e.key === 'down') { |
| 126 | e.preventDefault() |
| 127 | onExit() |
| 128 | return |
| 129 | } |
| 130 | if (e.key === 'up') { |
| 131 | e.preventDefault() |
| 132 | if (onExitUp) { |
| 133 | onExitUp() |
| 134 | } |
| 135 | return |
| 136 | } |
| 137 | if (e.key === 'escape') { |
| 138 | e.preventDefault() |
| 139 | if (onCancel) { |
| 140 | onCancel() |
| 141 | } else if (query.length > 0) { |
no test coverage detected