Skip to content

Commit fb98c1d

Browse files
NoopDogclaude
andauthored
feat: up-arrow recalls previous query in chat input (#193)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent cc71aea commit fb98c1d

File tree

1 file changed

+38
-1
lines changed

1 file changed

+38
-1
lines changed

app/components/Chat/chat.tsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,12 @@ export const Chat = (): JSX.Element => {
9090
const [messages, setMessages] = useState<Message[]>([]);
9191
const [input, setInput] = useState("");
9292
const [loading, setLoading] = useState(false);
93+
const [queryHistory, setQueryHistory] = useState<string[]>([]);
9394
const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement>(null);
9495
const listRef = useRef<HTMLDivElement>(null);
9596
const abortRef = useRef<AbortController | null>(null);
97+
const historyIndexRef = useRef(-1);
98+
const draftRef = useRef("");
9699
const { dimensions } = useLayoutDimensions();
97100
const headerHeight = dimensions.header.height;
98101

@@ -115,6 +118,9 @@ export const Chat = (): JSX.Element => {
115118
if (!query || loading) return;
116119

117120
setInput("");
121+
setQueryHistory((prev) => [...prev, query].slice(-50));
122+
historyIndexRef.current = -1;
123+
draftRef.current = "";
118124
setMessages((prev) => [...prev, { text: query, type: "user" }]);
119125
setLoading(true);
120126

@@ -168,9 +174,40 @@ export const Chat = (): JSX.Element => {
168174
if (e.key === "Enter" && !e.shiftKey) {
169175
e.preventDefault();
170176
handleSend();
177+
return;
178+
}
179+
180+
// Up/Down arrow: navigate query history when input is empty or
181+
// cursor is at the very start (avoids interfering with multiline editing).
182+
const el = e.currentTarget;
183+
const cursorAtStart = el.selectionStart === 0 && el.selectionEnd === 0;
184+
185+
if (e.key === "ArrowUp" && (input === "" || cursorAtStart)) {
186+
if (queryHistory.length === 0) return;
187+
e.preventDefault();
188+
if (historyIndexRef.current === -1) {
189+
draftRef.current = input;
190+
historyIndexRef.current = queryHistory.length - 1;
191+
} else if (historyIndexRef.current > 0) {
192+
historyIndexRef.current -= 1;
193+
}
194+
setInput(queryHistory[historyIndexRef.current]);
195+
} else if (
196+
e.key === "ArrowDown" &&
197+
historyIndexRef.current >= 0 &&
198+
cursorAtStart
199+
) {
200+
e.preventDefault();
201+
if (historyIndexRef.current < queryHistory.length - 1) {
202+
historyIndexRef.current += 1;
203+
setInput(queryHistory[historyIndexRef.current]);
204+
} else {
205+
historyIndexRef.current = -1;
206+
setInput(draftRef.current);
207+
}
171208
}
172209
},
173-
[handleSend]
210+
[handleSend, input, queryHistory]
174211
);
175212

176213
return (

0 commit comments

Comments
 (0)