Skip to content

Commit 96be6b9

Browse files
committed
[FIX] topbar: close font size dropdown and keep focus on the grid
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
1 parent 641d192 commit 96be6b9

File tree

6 files changed

+42
-2
lines changed

6 files changed

+42
-2
lines changed

src/components/font_size_editor/font_size_editor.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Component, useExternalListener, useRef, useState } from "@odoo/owl";
22
import { FONT_SIZES } from "../../constants";
33
import { clip } from "../../helpers/index";
4+
import { Store, useStore } from "../../store_engine";
5+
import { DOMFocusableElementStore } from "../../stores/DOM_focus_store";
46
import { SpreadsheetChildEnv } from "../../types/index";
57
import { css } from "../helpers/css";
68
import { isChildEvent } from "../helpers/dom_helpers";
@@ -62,7 +64,10 @@ export class FontSizeEditor extends Component<Props, SpreadsheetChildEnv> {
6264
private rootEditorRef = useRef("FontSizeEditor");
6365
private fontSizeListRef = useRef("fontSizeList");
6466

67+
private DOMFocusableElementStore!: Store<DOMFocusableElementStore>;
68+
6569
setup() {
70+
this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
6671
useExternalListener(window, "click", this.onExternalClick, { capture: true });
6772
}
6873

@@ -124,5 +129,12 @@ export class FontSizeEditor extends Component<Props, SpreadsheetChildEnv> {
124129
}
125130
this.props.onToggle?.();
126131
}
132+
if (ev.key === "Tab") {
133+
ev.preventDefault();
134+
ev.stopPropagation();
135+
this.closeFontList();
136+
this.DOMFocusableElementStore.focus();
137+
return;
138+
}
127139
}
128140
}

src/components/font_size_editor/font_size_editor.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
class=" o-font-size-editor d-flex align-items-center"
66
t-att-class="props.class"
77
title="Font Size"
8-
t-on-click="this.toggleFontList">
8+
t-on-click.stop="this.toggleFontList">
99
<input
1010
type="number"
1111
min="1"

src/components/grid_add_rows_footer/grid_add_rows_footer.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
<button
88
t-on-click="onConfirm"
99
t-att-disabled="state.errorFlag"
10-
class="o-button flex-grow-0 me-2">
10+
class="o-button flex-grow-0 me-2"
11+
tabindex="-1">
1112
Add
1213
</button>
1314
<input
@@ -19,6 +20,7 @@
1920
t-on-keydown.stop="onKeydown"
2021
t-on-pointerdown.stop=""
2122
t-on-input.stop="onInput"
23+
tabindex="-1"
2224
/>
2325
<span>more rows at the bottom</span>
2426
<ValidationMessages t-if="state.errorFlag" messages="errorMessages" msgType="'error'"/>

tests/grid/__snapshots__/grid_component.test.ts.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@ exports[`Grid component simple rendering snapshot 1`] = `
2929
>
3030
<button
3131
class="o-button flex-grow-0 me-2"
32+
tabindex="-1"
3233
>
3334
Add
3435
</button>
3536
<input
3637
class="o-grid-add-rows-input o-input mt-0 me-2"
38+
tabindex="-1"
3739
type="text"
3840
value="100"
3941
/>

tests/spreadsheet/__snapshots__/spreadsheet_component.test.ts.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,11 +771,13 @@ exports[`Simple Spreadsheet Component simple rendering snapshot 1`] = `
771771
>
772772
<button
773773
class="o-button flex-grow-0 me-2"
774+
tabindex="-1"
774775
>
775776
Add
776777
</button>
777778
<input
778779
class="o-grid-add-rows-input o-input mt-0 me-2"
780+
tabindex="-1"
779781
type="text"
780782
value="100"
781783
/>
@@ -1713,11 +1715,13 @@ exports[`components take the small screen into account 1`] = `
17131715
>
17141716
<button
17151717
class="o-button flex-grow-0 me-2"
1718+
tabindex="-1"
17161719
>
17171720
Add
17181721
</button>
17191722
<input
17201723
class="o-grid-add-rows-input o-input mt-0 me-2"
1724+
tabindex="-1"
17211725
type="text"
17221726
value="100"
17231727
/>

tests/top_bar_component.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
doubleClick,
3030
getElComputedStyle,
3131
getTextNodes,
32+
keyDown,
3233
simulateClick,
3334
triggerMouseEvent,
3435
} from "./test_helpers/dom_helper";
@@ -443,6 +444,25 @@ describe("TopBar component", () => {
443444
expect(getStyle(model, "A1").fontSize).toBe(8);
444445
});
445446

447+
test("Tab from font size editor closes the dropdown and moves focus to grid", async () => {
448+
const { fixture } = await mountSpreadsheet();
449+
const input = fixture.querySelector("input.o-font-size") as HTMLInputElement;
450+
input.focus();
451+
await nextTick();
452+
expect(fixture.querySelector(".o-popover .o-text-options")).toBeTruthy();
453+
await keyDown({ key: "Tab" });
454+
expect(fixture.querySelector(".o-popover .o-text-options")).toBeFalsy();
455+
const composerEl = fixture.querySelector<HTMLElement>(".o-grid-composer .o-composer")!;
456+
expect(document.activeElement).toBe(composerEl);
457+
});
458+
459+
test("Clicking the font size dropdown arrow focuses the input", async () => {
460+
const { fixture } = await mountSpreadsheet();
461+
const input = fixture.querySelector("input.o-font-size") as HTMLInputElement;
462+
await click(fixture, ".o-font-size-editor .o-icon");
463+
expect(document.activeElement).toBe(input);
464+
});
465+
446466
test("prevents default behavior of mouse wheel event on font size input", async () => {
447467
await mountParent();
448468
const fontSizeInput = fixture.querySelector("input.o-font-size") as HTMLInputElement;

0 commit comments

Comments
 (0)