From b7f77aff9bfcb4f280fcf08b4e64c6fd6c5a2e9c Mon Sep 17 00:00:00 2001 From: dhrp-odoo Date: Fri, 28 Nov 2025 04:57:52 +0000 Subject: [PATCH] [FIX] topbar: close font size dropdown and keep focus on the grid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pressing Tab in the font size editor could move focus to the hidden “add more rows” footer. The browser then auto-scrolled to that footer while the grid viewport state stayed unchanged, making the footer look like it was floating above the grid. We now handle Tab on the font size input: we prevent the default navigation, close the dropdown, and redirect focus back to the grid composer instead of the footer. This keeps the layout stable when tabbing from the toolbar. Alternative approaches considered but discarded: - Closing on blur and refocusing the grid: clicking the arrow caused the input to blur first, so the blur handler closed the dropdown and the arrow click immediately reopened it, making it impossible to close the dropdown. - Using mousedown to distinguish internal clicks: this fired before selecting an item in the dropdown, so the dropdown closed too early and the item click was never applied. Task: 5263792 X-original-commit: 99a94ac044eafd695c1a5f7d26aed6d97ab51a81 --- .../grid_add_rows_footer.xml | 4 +++- src/components/number_editor/number_editor.ts | 13 ++++++++++++ .../number_editor/number_editor.xml | 2 +- .../__snapshots__/grid_component.test.ts.snap | 2 ++ .../spreadsheet_component.test.ts.snap | 4 ++++ tests/top_bar_component.test.ts | 21 +++++++++++++++++++ 6 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/components/grid_add_rows_footer/grid_add_rows_footer.xml b/src/components/grid_add_rows_footer/grid_add_rows_footer.xml index 491bdda551..842d4c6495 100644 --- a/src/components/grid_add_rows_footer/grid_add_rows_footer.xml +++ b/src/components/grid_add_rows_footer/grid_add_rows_footer.xml @@ -7,7 +7,8 @@ more rows at the bottom diff --git a/src/components/number_editor/number_editor.ts b/src/components/number_editor/number_editor.ts index fa0c00f481..f89319b044 100644 --- a/src/components/number_editor/number_editor.ts +++ b/src/components/number_editor/number_editor.ts @@ -9,6 +9,8 @@ import { useState, } from "@odoo/owl"; import { clip } from "../../helpers/index"; +import { Store, useStore } from "../../store_engine"; +import { DOMFocusableElementStore } from "../../stores/DOM_focus_store"; import { isChildEvent } from "../helpers/dom_helpers"; import { Popover, PopoverProps } from "../popover"; @@ -56,7 +58,11 @@ export class NumberEditor extends Component { private rootEditorRef = useRef("NumberEditor"); private valueListRef = useRef("numberList"); + private DOMFocusableElementStore!: Store; + setup() { + this.DOMFocusableElementStore = useStore(DOMFocusableElementStore); + useExternalListener(window, "click", this.onExternalClick, { capture: true }); onWillUpdateProps((nextProps) => { if (this.inputRef.el && document.activeElement !== this.inputRef.el) { @@ -133,5 +139,12 @@ export class NumberEditor extends Component { } this.props.onToggle?.(); } + if (ev.key === "Tab") { + ev.preventDefault(); + ev.stopPropagation(); + this.closeList(); + this.DOMFocusableElementStore.focus(); + return; + } } } diff --git a/src/components/number_editor/number_editor.xml b/src/components/number_editor/number_editor.xml index 9c83f773b0..1cd4faf5fe 100644 --- a/src/components/number_editor/number_editor.xml +++ b/src/components/number_editor/number_editor.xml @@ -5,7 +5,7 @@ class="o-number-editor d-flex align-items-center" t-att-class="props.class" t-att-title="props.title" - t-on-click="this.toggleList"> + t-on-click.stop="this.toggleList"> diff --git a/tests/spreadsheet/__snapshots__/spreadsheet_component.test.ts.snap b/tests/spreadsheet/__snapshots__/spreadsheet_component.test.ts.snap index 44f7dd38ca..ac7c3affe2 100644 --- a/tests/spreadsheet/__snapshots__/spreadsheet_component.test.ts.snap +++ b/tests/spreadsheet/__snapshots__/spreadsheet_component.test.ts.snap @@ -835,11 +835,13 @@ exports[`Simple Spreadsheet Component simple rendering snapshot 1`] = ` > @@ -1842,11 +1844,13 @@ exports[`components take the small screen into account 1`] = ` > diff --git a/tests/top_bar_component.test.ts b/tests/top_bar_component.test.ts index be5c2e5422..c1767e3eee 100644 --- a/tests/top_bar_component.test.ts +++ b/tests/top_bar_component.test.ts @@ -30,6 +30,7 @@ import { doubleClick, getElComputedStyle, getTextNodes, + keyDown, simulateClick, triggerMouseEvent, } from "./test_helpers/dom_helper"; @@ -451,6 +452,26 @@ describe("TopBar component", () => { expect(getStyle(model, "A1").fontSize).toBe(8); }); + test("Tab from font size editor closes the dropdown and moves focus to grid", async () => { + const { fixture } = await mountSpreadsheet(); + const input = fixture.querySelector("input.o-font-size") as HTMLInputElement; + input.focus(); + await nextTick(); + expect(fixture.querySelector(".o-popover .o-text-options")).toBeTruthy(); + await keyDown({ key: "Tab" }); + expect(fixture.querySelector(".o-popover .o-text-options")).toBeFalsy(); + const composerEl = fixture.querySelector(".o-grid-composer .o-composer")!; + expect(document.activeElement).toBe(composerEl); + }); + + test("Clicking the number editor dropdown arrow focuses the input", async () => { + const { fixture } = await mountSpreadsheet(); + const input = fixture.querySelector("input.o-font-size") as HTMLInputElement; + const icon = fixture.querySelectorAll(".o-number-editor .o-icon")[0] as HTMLElement; + await click(icon); + expect(document.activeElement).toBe(input); + }); + test("prevents default behavior of mouse wheel event on font size input", async () => { await mountParent(); const fontSizeInput = fixture.querySelector("input.o-font-size") as HTMLInputElement;