From e99e8d59a5a36fdae9310f2190228d70a8417309 Mon Sep 17 00:00:00 2001 From: Molecule AI Core-UIUX Date: Sun, 17 May 2026 17:55:45 +0000 Subject: [PATCH 1/2] fix(canvas/mobile): WCAG 2.4.7 focus-visible rings on all mobile canvas buttons Adds keyboard focus indicators (focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset) to every keyboard-navigable button across the mobile canvas layer. Buttons using inline style props now carry a Tailwind className pair that shows the ring on keyboard focus without affecting mouse/touch users. Components fixed: - MobileChat: Back, More, tab-switch, Retry, Remove file, Attach, Send - MobileHome: Spawn FAB - MobileSpawn: Close, template select, tier select, Spawn agent - MobileMe: Accent swatches, Theme/Density segmented controls - MobileDetail: Back, More, tab-switch, Open chat CTA - MobileComms: Filter chips (All, Errors) - components.tsx: AgentCard, FilterChips Refs #1384 Co-Authored-By: Claude Opus 4.7 --- canvas/src/components/mobile/MobileChat.tsx | 7 +++++++ canvas/src/components/mobile/MobileComms.tsx | 1 + canvas/src/components/mobile/MobileDetail.tsx | 5 ++++- canvas/src/components/mobile/MobileHome.tsx | 1 + canvas/src/components/mobile/MobileMe.tsx | 2 ++ canvas/src/components/mobile/MobileSpawn.tsx | 4 ++++ canvas/src/components/mobile/components.tsx | 2 ++ 7 files changed, 21 insertions(+), 1 deletion(-) diff --git a/canvas/src/components/mobile/MobileChat.tsx b/canvas/src/components/mobile/MobileChat.tsx index 375bd37a8..c05c7bf2c 100644 --- a/canvas/src/components/mobile/MobileChat.tsx +++ b/canvas/src/components/mobile/MobileChat.tsx @@ -339,6 +339,7 @@ export function MobileChat({ type="button" onClick={onBack} aria-label="Back" + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ width: 36, height: 36, @@ -385,6 +386,7 @@ export function MobileChat({ - @@ -183,6 +184,7 @@ export function MobileDetail({ key={t.id} type="button" onClick={() => setTab(t.id)} + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ padding: "8px 14px", borderRadius: 999, @@ -215,6 +217,7 @@ export function MobileDetail({ type="button" onClick={onChat} data-testid="mobile-chat-cta" + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2" style={{ width: "100%", height: 52, diff --git a/canvas/src/components/mobile/MobileHome.tsx b/canvas/src/components/mobile/MobileHome.tsx index 271fa511f..2569ada91 100644 --- a/canvas/src/components/mobile/MobileHome.tsx +++ b/canvas/src/components/mobile/MobileHome.tsx @@ -183,6 +183,7 @@ export function MobileHome({ type="button" onClick={onSpawn} aria-label="Spawn new agent" + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2" style={{ position: "absolute", right: 24, diff --git a/canvas/src/components/mobile/MobileMe.tsx b/canvas/src/components/mobile/MobileMe.tsx index c1735083d..ca859e9be 100644 --- a/canvas/src/components/mobile/MobileMe.tsx +++ b/canvas/src/components/mobile/MobileMe.tsx @@ -83,6 +83,7 @@ export function MobileMe({ type="button" onClick={() => setAccent(c)} aria-label={`Set accent ${c}`} + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ width: 36, height: 36, @@ -173,6 +174,7 @@ function SegmentedRow({ key={o.id} type="button" onClick={() => onChange(o.id)} + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ flex: 1, padding: "10px 8px", diff --git a/canvas/src/components/mobile/MobileSpawn.tsx b/canvas/src/components/mobile/MobileSpawn.tsx index 7ee62e89d..752b37f94 100644 --- a/canvas/src/components/mobile/MobileSpawn.tsx +++ b/canvas/src/components/mobile/MobileSpawn.tsx @@ -148,6 +148,7 @@ export function MobileSpawn({ dark, onClose }: { dark: boolean; onClose: () => v type="button" onClick={onClose} aria-label="Close" + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ width: 32, height: 32, @@ -214,6 +215,7 @@ export function MobileSpawn({ dark, onClose }: { dark: boolean; onClose: () => v setTplId(t.id); setTier(tCode); }} + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ background: on ? dark @@ -330,6 +332,7 @@ export function MobileSpawn({ dark, onClose }: { dark: boolean; onClose: () => v key={t} type="button" onClick={() => setTier(t)} + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ flex: 1, padding: "10px 8px", @@ -377,6 +380,7 @@ export function MobileSpawn({ dark, onClose }: { dark: boolean; onClose: () => v type="button" onClick={handleSpawn} disabled={busy || !tplId || templates.length === 0} + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2" style={{ width: "100%", height: 52, diff --git a/canvas/src/components/mobile/components.tsx b/canvas/src/components/mobile/components.tsx index 592604a52..4d06ca210 100644 --- a/canvas/src/components/mobile/components.tsx +++ b/canvas/src/components/mobile/components.tsx @@ -291,6 +291,7 @@ export function AgentCard({ data-testid="workspace-card" aria-label={`${agent.name}, status: ${agent.status}, tier ${agent.tier}${agent.remote ? ", remote" : ""}`} onClick={onClick} + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ display: "block", width: "100%", @@ -444,6 +445,7 @@ export function FilterChips({ type="button" aria-checked={on} onClick={() => onChange(o.id)} + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ display: "inline-flex", alignItems: "center", -- 2.52.0 From 5aece16017c07cac91a5ebcdc303418d45f13cfc Mon Sep 17 00:00:00 2001 From: Molecule AI Core-UIUX Date: Sun, 17 May 2026 18:13:48 +0000 Subject: [PATCH 2/2] fix(canvas/mobile): WCAG 2.4.7 focus-visible + aria-label on MobileCanvas buttons Adds focus-visible ring + aria-label to the three inline-styled buttons in MobileCanvas.tsx: - Reset zoom: focus-visible ring - Agent node: aria-label="Open {name}" + focus-visible ring (was missing both) - Spawn FAB: focus-visible ring Also adds MobileCanvas to the PR scope; refs #1395. Co-Authored-By: Claude Opus 4.7 --- canvas/src/components/mobile/MobileCanvas.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/canvas/src/components/mobile/MobileCanvas.tsx b/canvas/src/components/mobile/MobileCanvas.tsx index acdaa1689..53a462c4c 100644 --- a/canvas/src/components/mobile/MobileCanvas.tsx +++ b/canvas/src/components/mobile/MobileCanvas.tsx @@ -205,6 +205,7 @@ export function MobileCanvas({ type="button" onClick={resetView} aria-label="Reset zoom" + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ position: "absolute", right: 14, @@ -272,6 +273,8 @@ export function MobileCanvas({ key={l.agent.id} type="button" onClick={() => onOpen(l.agent.id)} + aria-label={`Open ${l.agent.name}`} + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1" style={{ position: "absolute", left: `${l.x}%`, @@ -376,6 +379,7 @@ export function MobileCanvas({ type="button" onClick={onSpawn} aria-label="Spawn new agent" + className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2" style={{ position: "absolute", right: 24, -- 2.52.0