Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 24 additions & 14 deletions src/ink/hooks/use-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,31 @@ type Options = {
const useInput = (inputHandler: Handler, options: Options = {}) => {
const { setRawMode, internal_exitOnCtrlC, internal_eventEmitter } = useStdin()

// useLayoutEffect (not useEffect) so that raw mode is enabled synchronously
// during React's commit phase, before render() returns. With useEffect, raw
// mode setup is deferred to the next event loop tick via React's scheduler,
// leaving the terminal in cooked mode — keystrokes echo and the cursor is
// visible until the effect fires.
useLayoutEffect(() => {
if (options.isActive === false) {
return
}
// useLayoutEffect (not useEffect) so that raw mode is enabled synchronously
// during React's commit phase, before render() returns. With useEffect, raw
// mode setup is deferred to the next event loop tick via React's scheduler,
// leaving the terminal in cooked mode — keystrokes echo and the cursor is
// visible until the effect fires.
useLayoutEffect(() => {
if (options.isActive === false) {
return
}

setRawMode(true)
setRawMode(true)

return () => {
setRawMode(false)
}
}, [options.isActive, setRawMode])
return () => {
// Re-check isActive so we skip the (false → false) path
// produced by Ink's PreserveFocus unmount/remount cycles
// during MCP async re-render churn. A single commit round-trip
// unmounts the leaf and re-mounts it before the next tick;
// keeping raw mode on avoids deregistering the stdin listener.
if (options.isActive !== false) {
return
}

setRawMode(false)
}
}, [options.isActive, setRawMode])

// Register the listener once on mount so its slot in the EventEmitter's
// listener array is stable. If isActive were in the effect's deps, the
Expand Down Expand Up @@ -100,3 +109,4 @@ const useInput = (inputHandler: Handler, options: Options = {}) => {
}

export default useInput