From f6e9deb13f2810a8ad5e1af497683903344b310b Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Tue, 23 Jun 2026 10:40:37 -0700 Subject: [PATCH] FN-6958: stop auto-focusing Planning Mode composer Planning Mode now opens without forcing focus into the initial text area.\n\n- Remove the open-time autofocus effect while preserving explicit textarea focus behavior.\n- Cover mobile, embedded desktop, and initialPlan handoff behavior with regression tests.\n- Add a patch changeset for the published CLI package.\n\nFiles changed:\n .changeset/FN-6958-planning-focus.md | 5 ++\n .../dashboard/app/components/PlanningModeModal.tsx | 10 ++--\n .../__tests__/PlanningModeModal.initial.test.tsx | 69 ++++++++++++++++++++++\n 3 files changed, 78 insertions(+), 6 deletions(-) Fusion-Task-Id: FN-6958 Fusion-Task-Lineage: df030f3f-c9ca-4420-8618-bc3ec44d6e12 --- .changeset/FN-6958-planning-focus.md | 5 ++ .../app/components/PlanningModeModal.tsx | 10 ++- .../PlanningModeModal.initial.test.tsx | 69 +++++++++++++++++++ 3 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 .changeset/FN-6958-planning-focus.md diff --git a/.changeset/FN-6958-planning-focus.md b/.changeset/FN-6958-planning-focus.md new file mode 100644 index 0000000000..4e2c405b4e --- /dev/null +++ b/.changeset/FN-6958-planning-focus.md @@ -0,0 +1,5 @@ +--- +"@runfusion/fusion": patch +--- + +Stop Planning Mode from automatically focusing the initial text entry when it opens, preventing mobile keyboards from appearing until the user explicitly focuses the textarea. diff --git a/packages/dashboard/app/components/PlanningModeModal.tsx b/packages/dashboard/app/components/PlanningModeModal.tsx index f86a01efb1..49bcdb204a 100644 --- a/packages/dashboard/app/components/PlanningModeModal.tsx +++ b/packages/dashboard/app/components/PlanningModeModal.tsx @@ -821,12 +821,10 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat projectId, ]); - // Focus textarea when opening - useEffect(() => { - if (isOpen && view.type === "initial") { - textareaRef.current?.focus(); - } - }, [isOpen, view.type]); + /* + FNXC:PlanningFocus 2026-06-23-00:00: + Viewing Planning Mode must not auto-focus the initial composer because mobile browsers open the keyboard before the user chooses to type. Keep the textarea ref for autosize and explicit user focus only; populated initialPlan handoffs still auto-start through the separate effect below. + */ useEffect(() => { if (!isOpen) { diff --git a/packages/dashboard/app/components/__tests__/PlanningModeModal.initial.test.tsx b/packages/dashboard/app/components/__tests__/PlanningModeModal.initial.test.tsx index 938854a6e0..0675fd0274 100644 --- a/packages/dashboard/app/components/__tests__/PlanningModeModal.initial.test.tsx +++ b/packages/dashboard/app/components/__tests__/PlanningModeModal.initial.test.tsx @@ -216,6 +216,75 @@ describe("PlanningModeModal", () => { expect(screen.queryByText("Planning Mode")).toBeNull(); }); + it("does not auto-focus the initial textarea on mobile open until the user focuses it", () => { + mockViewport("mobile"); + + render( + + ); + + const textarea = screen.getByLabelText("What do you want to build?") as HTMLTextAreaElement; + expect(document.activeElement).not.toBe(textarea); + + act(() => { + textarea.focus(); + }); + + expect(document.activeElement).toBe(textarea); + }); + + it("does not auto-focus the initial textarea in embedded desktop presentation", () => { + render( + + ); + + const textarea = screen.getByLabelText("What do you want to build?") as HTMLTextAreaElement; + expect(textarea.value).toBe(""); + expect(document.activeElement).not.toBe(textarea); + }); + + it("auto-starts populated initialPlan handoffs without focusing the initial textarea", async () => { + const focusSpy = vi.spyOn(HTMLTextAreaElement.prototype, "focus"); + + try { + render( + + ); + + await waitFor(() => { + expect(mockStartPlanningStreaming).toHaveBeenCalledWith("Build a login system from handoff", undefined, undefined, { + planningDepth: "medium", + customQuestionCount: undefined, + }, undefined); + }); + + expect(focusSpy).not.toHaveBeenCalled(); + } finally { + focusSpy.mockRestore(); + } + }); + it("mobile close path blurs focused input and resets viewport scroll", () => { mockViewport("mobile"); const scrollToSpy = vi.spyOn(window, "scrollTo").mockImplementation(() => undefined);