fix(FN-000): harden mobile terminal focus capture for soft keyboard
This commit is contained in:
@@ -696,6 +696,14 @@ export function TerminalModal({ isOpen, onClose, initialCommand, projectId }: Te
|
||||
|
||||
if (!helperTextarea) return;
|
||||
|
||||
// Mobile Safari/Chrome soft keyboard heuristics are stricter than desktop:
|
||||
// keep attributes explicit and focus from a direct user gesture.
|
||||
helperTextarea.autocapitalize = "off";
|
||||
helperTextarea.autocomplete = "off";
|
||||
(helperTextarea as unknown as { autocorrect: string }).autocorrect = "off";
|
||||
helperTextarea.spellcheck = false;
|
||||
helperTextarea.setAttribute("inputmode", "text");
|
||||
|
||||
try {
|
||||
helperTextarea.focus({ preventScroll: true });
|
||||
} catch {
|
||||
@@ -981,8 +989,9 @@ export function TerminalModal({ isOpen, onClose, initialCommand, projectId }: Te
|
||||
ref={terminalRef}
|
||||
className="terminal-xterm"
|
||||
data-testid="terminal-xterm"
|
||||
onPointerDown={handleTerminalGestureFocus}
|
||||
onTouchStart={handleTerminalGestureFocus}
|
||||
onPointerDownCapture={handleTerminalGestureFocus}
|
||||
onTouchStartCapture={handleTerminalGestureFocus}
|
||||
onClickCapture={handleTerminalGestureFocus}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3603,7 +3603,7 @@ describe("TerminalModal — xterm focus initialization (FN-1602)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("focuses xterm helper textarea on user pointer gesture", async () => {
|
||||
it("focuses xterm helper textarea on user pointer gesture (capture phase)", async () => {
|
||||
render(<TerminalModal isOpen={true} onClose={mockOnClose} />);
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -3617,11 +3617,17 @@ describe("TerminalModal — xterm focus initialization (FN-1602)", () => {
|
||||
const setSelectionRangeSpy = vi.spyOn(helperTextarea, "setSelectionRange");
|
||||
terminalDiv.appendChild(helperTextarea);
|
||||
|
||||
fireEvent.pointerDown(terminalDiv);
|
||||
// Simulate xterm child event handlers stopping bubble propagation.
|
||||
const child = document.createElement("div");
|
||||
child.addEventListener("pointerdown", (event) => event.stopPropagation());
|
||||
terminalDiv.appendChild(child);
|
||||
|
||||
fireEvent.pointerDown(child);
|
||||
|
||||
expect(mockTerminalInstance.focus).toHaveBeenCalled();
|
||||
expect(focusSpy).toHaveBeenCalled();
|
||||
expect(setSelectionRangeSpy).toHaveBeenCalledWith(0, 0);
|
||||
expect(helperTextarea.getAttribute("inputmode")).toBe("text");
|
||||
});
|
||||
|
||||
it("focuses xterm helper textarea on touch gesture", async () => {
|
||||
@@ -3640,6 +3646,10 @@ describe("TerminalModal — xterm focus initialization (FN-1602)", () => {
|
||||
fireEvent.touchStart(terminalDiv);
|
||||
|
||||
expect(focusSpy).toHaveBeenCalled();
|
||||
expect(helperTextarea.autocapitalize).toBe("off");
|
||||
expect(helperTextarea.autocomplete).toBe("off");
|
||||
expect(helperTextarea.autocorrect).toBe("off");
|
||||
expect(helperTextarea.spellcheck).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user