diff --git a/.changeset/auto-expand-chat-input.md b/.changeset/auto-expand-chat-input.md new file mode 100644 index 0000000..a2e68ed --- /dev/null +++ b/.changeset/auto-expand-chat-input.md @@ -0,0 +1,6 @@ +--- +"think-app": patch +"think-extension": patch +--- + +Add auto-expanding chat input that grows as users type diff --git a/app/src/components/ChatInput.tsx b/app/src/components/ChatInput.tsx index 1415c2f..67572e2 100644 --- a/app/src/components/ChatInput.tsx +++ b/app/src/components/ChatInput.tsx @@ -20,7 +20,7 @@ export function ChatInput({ placeholder = "Type your message...", className, }: ChatInputProps) { - const inputRef = useRef(null); + const inputRef = useRef(null); const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey) { @@ -29,6 +29,20 @@ export function ChatInput({ } }; + // Auto-resize textarea based on content + const adjustHeight = () => { + const textarea = inputRef.current; + if (textarea) { + textarea.style.height = "auto"; + textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`; + } + }; + + // Adjust height when value changes + useEffect(() => { + adjustHeight(); + }, [value]); + // Auto-focus input after message submission (when loading completes) useEffect(() => { if (!isLoading && inputRef.current) { @@ -39,7 +53,7 @@ export function ChatInput({ return (
- onChange(e.target.value)} onKeyDown={handleKeyDown} placeholder={placeholder} disabled={isLoading} + rows={1} className={cn( - "flex-1 bg-transparent px-4 py-2 text-base", + "flex-1 bg-transparent px-4 py-2 text-base min-h-[44px] max-h-[200px] resize-none", "placeholder:text-muted-foreground/60", "focus:outline-none", "disabled:opacity-50" diff --git a/extension/src/sidebar/ChatSidebar.tsx b/extension/src/sidebar/ChatSidebar.tsx index d7f9056..cfc7d0b 100644 --- a/extension/src/sidebar/ChatSidebar.tsx +++ b/extension/src/sidebar/ChatSidebar.tsx @@ -87,7 +87,7 @@ export function ChatSidebar({ pageContent, pageUrl, pageTitle, onClose }: ChatSi // Follow-up suggestions from LLM const [followupSuggestions, setFollowupSuggestions] = useState([]); const messagesEndRef = useRef(null); - const inputRef = useRef(null); + const inputRef = useRef(null); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); @@ -101,6 +101,19 @@ export function ChatSidebar({ pageContent, pageUrl, pageTitle, onClose }: ChatSi inputRef.current?.focus(); }, []); + // Auto-resize textarea based on content + const adjustHeight = () => { + const textarea = inputRef.current; + if (textarea) { + textarea.style.height = 'auto'; + textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`; + } + }; + + useEffect(() => { + adjustHeight(); + }, [input]); + const sendMessage = async (messageText?: string) => { const userMessage = (messageText || input).trim(); if (!userMessage || loading) return; @@ -420,16 +433,16 @@ export function ChatSidebar({ pageContent, pageUrl, pageTitle, onClose }: ChatSi {/* Input */}
-
- +