Skip to content

Commit befebc8

Browse files
committed
fix(bots): Tab reaches the colours in Safari and the desktop app
WebKit's Tab passes over a radio that has no tabindex of its own, so in Safari and in the macOS desktop app's window Tab never reached the colours. The chosen colour now carries tabindex 0 and the others -1, so the group is still one stop and the arrow keys move through it.
1 parent 76b3e3c commit befebc8

2 files changed

Lines changed: 23 additions & 1 deletion

File tree

‎app/src/components/bot-profile/look.tsx‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export const SAVE_AFTER_MS = 700;
5959
* whoever may edit the Bot, the people who may also rename it.
6060
*
6161
* The colours are native radios, so the group is one stop for Tab and the arrow keys move through
62-
* it, as they do in any radio group. Moving through them only previews: the face shows each colour
62+
* it, as they do in any radio group. The chosen one carries the stop as its tabindex, which Safari
63+
* needs to reach a radio by Tab at all. Moving through them only previews: the face shows each colour
6364
* at once, and the one the person stops on is saved after a short pause, or as soon as focus leaves
6465
* the group, so browsing restyles the Bot for nobody else and saves it once. New face saves at once.
6566
* Either can be taken back with Undo, which saves the look from before. One that can't be saved
@@ -244,6 +245,10 @@ export function LookSection({ agent }: { agent: AgentProfile }) {
244245
className="peer sr-only"
245246
name={group}
246247
onChange={() => pick(option)}
248+
// Safari's Tab, and the desktop app's on a Mac, passes over a radio unless it
249+
// has a tabindex of its own. The chosen colour has one, so the group stays a
250+
// single stop, and the arrow keys move through it from there.
251+
tabIndex={option === colour ? 0 : -1}
247252
type="radio"
248253
value={option}
249254
/>

‎app/tests/bot-look.test.tsx‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,23 @@ test("the Look section shows the Bot's face large, and its colour named and chos
275275
expect(seeds(view).preview).toEqual(["expenses"]);
276276
});
277277

278+
test("Tab reaches the colours in any browser, at the chosen one, and stops there once", async () => {
279+
serve();
280+
const { view, user } = draw();
281+
const look = await lookOf(view);
282+
// Safari's Tab passes over a radio with no tabindex of its own, so the chosen colour has one.
283+
const stops = () =>
284+
(look.getAllByRole("radio") as HTMLInputElement[]).map((radio) =>
285+
radio.getAttribute("tabindex"),
286+
);
287+
const only = (at: number) =>
288+
COLOURS.map((_, index) => (index === at ? "0" : "-1"));
289+
expect(stops()).toEqual(only(COLOURS.indexOf("Blue")));
290+
291+
await user.click(look.getByRole("radio", { name: "Green" }));
292+
expect(stops()).toEqual(only(COLOURS.indexOf("Green")));
293+
});
294+
278295
test("a colour shows at once, saves after a pause, and every avatar of the Bot follows", async () => {
279296
serve();
280297
const { view, user } = draw();

0 commit comments

Comments
 (0)