Make the action input auto-grow up to ~4 lines

Swap the single-line action <input> for a <textarea> that grows with its
content (capped at ~4 lines, then scrolls) and shrinks back after send.
Enter still sends; Shift+Enter inserts a newline. Buttons stay bottom-aligned
as it grows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
This commit is contained in:
parththakkar106
2026-07-21 01:41:00 +05:30
co-authored by Claude Opus 4.8
parent 8a1650c0d4
commit 92044a53c4
2 changed files with 27 additions and 4 deletions
+17 -3
View File
@@ -612,6 +612,16 @@ export default function Play() {
const storyEndRef = useRef(null)
const abortRef = useRef(null)
const pinnedRef = useRef(true) // autoscroll only while the reader is at the bottom
const inputRef = useRef(null)
// Grow the action box with its content (CSS caps it at ~4 lines, then
// scrolls); shrinks back after send() clears the text.
useEffect(() => {
const el = inputRef.current
if (!el) return
el.style.height = 'auto'
el.style.height = `${el.scrollHeight}px`
}, [input])
useEffect(() => {
api.getAdventure(id)
@@ -863,8 +873,9 @@ export default function Play() {
</button>
))}
</div>
<input
type="text"
<textarea
ref={inputRef}
rows={1}
value={input}
disabled={busy}
placeholder={
@@ -873,7 +884,10 @@ export default function Play() {
: 'What happens next?'
}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => { if (e.key === 'Enter' && !busy) send() }}
// Enter sends; Shift+Enter inserts a newline.
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey && !busy) { e.preventDefault(); send() }
}}
/>
{busy ? (
<button className="danger" onClick={stopGeneration}>■ Stop</button>