feat: Story 14 - Auto-focus chat input on startup
Implemented Story 14: Auto-focus Chat Input - Added inputRef using useRef<HTMLInputElement> - Added useEffect to focus input on component mount - Input now automatically receives focus when chat loads - Cursor is visible and blinking immediately - Users can start typing without clicking into the field Updated Specs - Added Input Focus Management section to UI_UX.md - Specified auto-focus behavior and requirements - Provided implementation example
This commit is contained in:
@@ -157,3 +157,35 @@ Integrate syntax highlighting into markdown code blocks rendered by the assistan
|
|||||||
```
|
```
|
||||||
* Ensure syntax highlighted code blocks are left-aligned
|
* Ensure syntax highlighted code blocks are left-aligned
|
||||||
* Test with various code samples to ensure proper rendering
|
* Test with various code samples to ensure proper rendering
|
||||||
|
|
||||||
|
## Input Focus Management
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
When the app loads with a project selected, users need to click into the chat input box before they can start typing. This adds unnecessary friction to the user experience.
|
||||||
|
|
||||||
|
### Solution: Auto-focus on Component Mount
|
||||||
|
The chat input field should automatically receive focus when the chat component mounts, allowing users to immediately start typing.
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
1. **Auto-focus:** Input field receives focus automatically when chat component loads
|
||||||
|
2. **Visible Cursor:** Cursor should be visible and blinking in the input field
|
||||||
|
3. **Immediate Typing:** User can start typing without clicking into the field
|
||||||
|
4. **Non-intrusive:** Should not interfere with other UI interactions or accessibility
|
||||||
|
5. **Timing:** Focus should be set after the component fully mounts
|
||||||
|
|
||||||
|
### Implementation Notes
|
||||||
|
* Use React `useRef` to create a reference to the input element
|
||||||
|
* Use `useEffect` with empty dependency array to run once on mount
|
||||||
|
* Call `inputRef.current?.focus()` in the effect
|
||||||
|
* Ensure the ref is properly attached to the input element
|
||||||
|
* Example implementation:
|
||||||
|
```tsx
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <input ref={inputRef} ... />
|
||||||
|
```
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Story: Auto-focus Chat Input on Startup
|
||||||
|
|
||||||
|
## User Story
|
||||||
|
**As a** User
|
||||||
|
**I want** the cursor to automatically appear in the chat input box when the app starts
|
||||||
|
**So that** I can immediately start typing without having to click into the input field first.
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
* [x] When the app loads and a project is selected, the chat input box should automatically receive focus
|
||||||
|
* [x] The cursor should be visible and blinking in the input field
|
||||||
|
* [x] User can immediately start typing without any additional clicks
|
||||||
|
* [x] Focus should be set after the component mounts
|
||||||
|
* [x] Should not interfere with other UI interactions
|
||||||
|
|
||||||
|
## Out of Scope
|
||||||
|
* Auto-focus when switching between projects (only on initial load)
|
||||||
|
* Remembering cursor position across sessions
|
||||||
|
* Focus management for other input fields
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
* Use React `useEffect` hook to set focus on component mount
|
||||||
|
* Use a ref to reference the input element
|
||||||
|
* Call `inputRef.current?.focus()` after component renders
|
||||||
|
* Ensure it works consistently across different browsers
|
||||||
|
|
||||||
|
## Related Functional Specs
|
||||||
|
* Functional Spec: UI/UX
|
||||||
@@ -19,6 +19,7 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
|||||||
const [enableTools, setEnableTools] = useState(true);
|
const [enableTools, setEnableTools] = useState(true);
|
||||||
const [availableModels, setAvailableModels] = useState<string[]>([]);
|
const [availableModels, setAvailableModels] = useState<string[]>([]);
|
||||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
invoke<string[]>("get_ollama_models")
|
invoke<string[]>("get_ollama_models")
|
||||||
@@ -61,6 +62,10 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
|||||||
|
|
||||||
useEffect(scrollToBottom, [messages]);
|
useEffect(scrollToBottom, [messages]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const sendMessage = async () => {
|
const sendMessage = async () => {
|
||||||
if (!input.trim() || loading) return;
|
if (!input.trim() || loading) return;
|
||||||
|
|
||||||
@@ -454,6 +459,7 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
ref={inputRef}
|
||||||
value={input}
|
value={input}
|
||||||
onChange={(e) => setInput(e.target.value)}
|
onChange={(e) => setInput(e.target.value)}
|
||||||
onKeyDown={(e) => e.key === "Enter" && sendMessage()}
|
onKeyDown={(e) => e.key === "Enter" && sendMessage()}
|
||||||
|
|||||||
Reference in New Issue
Block a user