From b8c4c6686b2e85e68c23106ceabaf6f0932653c8 Mon Sep 17 00:00:00 2001 From: Vladislav Forsh Date: Fri, 27 Feb 2026 18:56:13 +0300 Subject: [PATCH] fix(workspaces): focus textarea after recent path select --- .../MobileRemoteWorkspacePrompt.test.tsx | 43 +++++++++++++++++++ .../MobileRemoteWorkspacePrompt.tsx | 18 +++++++- 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 src/features/workspaces/components/MobileRemoteWorkspacePrompt.test.tsx diff --git a/src/features/workspaces/components/MobileRemoteWorkspacePrompt.test.tsx b/src/features/workspaces/components/MobileRemoteWorkspacePrompt.test.tsx new file mode 100644 index 000000000..a57377160 --- /dev/null +++ b/src/features/workspaces/components/MobileRemoteWorkspacePrompt.test.tsx @@ -0,0 +1,43 @@ +// @vitest-environment jsdom +import { useState } from "react"; +import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { MobileRemoteWorkspacePrompt } from "./MobileRemoteWorkspacePrompt"; + +afterEach(() => { + cleanup(); +}); + +describe("MobileRemoteWorkspacePrompt", () => { + it("focuses paths textarea and moves caret to end after selecting a recent path", async () => { + const recentPath = "/Users/vlad/dev/codex-monitor/cm"; + function PromptHarness() { + const [value, setValue] = useState(""); + return ( + { + setValue((prev) => (prev.length > 0 ? `${prev}\n${path}` : path)); + }} + onCancel={vi.fn()} + onConfirm={vi.fn()} + /> + ); + } + render(); + + const recentPathButton = screen.getByRole("button", { name: recentPath }); + fireEvent.click(recentPathButton); + + const textarea = screen.getByLabelText("Paths"); + await waitFor(() => { + expect(document.activeElement).toBe(textarea); + const expectedPosition = recentPath.length; + expect((textarea as HTMLTextAreaElement).selectionStart).toBe(expectedPosition); + expect((textarea as HTMLTextAreaElement).selectionEnd).toBe(expectedPosition); + }); + }); +}); diff --git a/src/features/workspaces/components/MobileRemoteWorkspacePrompt.tsx b/src/features/workspaces/components/MobileRemoteWorkspacePrompt.tsx index 5bcc0bcb1..0fed5447b 100644 --- a/src/features/workspaces/components/MobileRemoteWorkspacePrompt.tsx +++ b/src/features/workspaces/components/MobileRemoteWorkspacePrompt.tsx @@ -21,9 +21,18 @@ export function MobileRemoteWorkspacePrompt({ onConfirm, }: MobileRemoteWorkspacePromptProps) { const textareaRef = useRef(null); + const focusTextareaAtEnd = () => { + const textarea = textareaRef.current; + if (!textarea) { + return; + } + textarea.focus(); + const end = textarea.value.length; + textarea.setSelectionRange(end, end); + }; useEffect(() => { - textareaRef.current?.focus(); + focusTextareaAtEnd(); }, []); return ( @@ -63,7 +72,12 @@ export function MobileRemoteWorkspacePrompt({ key={path} type="button" className="mobile-remote-workspace-modal-recent-item" - onClick={() => onRecentPathSelect(path)} + onClick={() => { + onRecentPathSelect(path); + requestAnimationFrame(() => { + focusTextareaAtEnd(); + }); + }} > {path}