fix(canvas/mobile): WCAG 2.4.7 focus-visible rings on all mobile interactive buttons
Some checks failed
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 3s
cascade-list-drift-gate / check (pull_request) Successful in 4s
CI / Detect changes (pull_request) Successful in 4s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 9s
E2E API Smoke Test / detect-changes (pull_request) Successful in 6s
E2E Chat / detect-changes (pull_request) Successful in 7s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 7s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 5s
Harness Replays / detect-changes (pull_request) Successful in 5s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m8s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 3s
CI / Platform (Go) (pull_request) Successful in 4m40s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m1s
CI / Canvas (Next.js) (pull_request) Failing after 5m44s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 1m6s
publish-runtime-autobump / bump-and-tag (pull_request) Has been skipped
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 50s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 4s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 4s
gate-check-v3 / gate-check (pull_request) Successful in 3s
CI / all-required (pull_request) Failing after 5m22s
qa-review / approved (pull_request) Failing after 3s
security-review / approved (pull_request) Failing after 3s
sop-tier-check / tier-check (pull_request) Successful in 4s
publish-runtime-autobump / pr-validate (pull_request) Successful in 26s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m5s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 2s
Harness Replays / Harness Replays (pull_request) Successful in 2s
CI / Python Lint & Test (pull_request) Successful in 6m35s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 1m7s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 1m46s
E2E Chat / E2E Chat (pull_request) Failing after 4m52s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 8m25s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4
sop-checklist / na-declarations (pull_request) N/A: (none)
Some checks failed
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 3s
cascade-list-drift-gate / check (pull_request) Successful in 4s
CI / Detect changes (pull_request) Successful in 4s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 9s
E2E API Smoke Test / detect-changes (pull_request) Successful in 6s
E2E Chat / detect-changes (pull_request) Successful in 7s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 7s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 5s
Harness Replays / detect-changes (pull_request) Successful in 5s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m8s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 3s
CI / Platform (Go) (pull_request) Successful in 4m40s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m1s
CI / Canvas (Next.js) (pull_request) Failing after 5m44s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 1m6s
publish-runtime-autobump / bump-and-tag (pull_request) Has been skipped
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 50s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 4s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 4s
gate-check-v3 / gate-check (pull_request) Successful in 3s
CI / all-required (pull_request) Failing after 5m22s
qa-review / approved (pull_request) Failing after 3s
security-review / approved (pull_request) Failing after 3s
sop-tier-check / tier-check (pull_request) Successful in 4s
publish-runtime-autobump / pr-validate (pull_request) Successful in 26s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m5s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 2s
Harness Replays / Harness Replays (pull_request) Successful in 2s
CI / Python Lint & Test (pull_request) Successful in 6m35s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 1m7s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 1m46s
E2E Chat / E2E Chat (pull_request) Failing after 4m52s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 8m25s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4
sop-checklist / na-declarations (pull_request) N/A: (none)
Adds focus-visible:ring-2 to keyboard-navigable buttons across all mobile components that previously relied on inline styles only: - MobileChat.tsx: Back, More, tab-switch, Retry, Remove file, Attach, Send - MobileHome.tsx: Spawn FAB - MobileSpawn.tsx: Close, template select, tier select, Spawn agent - MobileMe.tsx: Accent swatches, Theme/Density segmented controls - MobileDetail.tsx: Back, More, tab-switch, Open chat CTA - MobileComms.tsx: filter chips - components.tsx: AgentCard, FilterChips Tailwind focus-visible utilities applied alongside existing inline styles; no visual change for mouse users. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
89d510f373
commit
7f322be1d0
@ -339,6 +339,7 @@ export function MobileChat({
|
||||
type="button"
|
||||
onClick={onBack}
|
||||
aria-label="Back"
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
@ -385,6 +386,7 @@ export function MobileChat({
|
||||
<button
|
||||
type="button"
|
||||
aria-label="More"
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
@ -415,6 +417,7 @@ export function MobileChat({
|
||||
key={t.id}
|
||||
type="button"
|
||||
onClick={() => setTab(t.id)}
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
padding: "4px 0 8px",
|
||||
border: "none",
|
||||
@ -478,6 +481,7 @@ export function MobileChat({
|
||||
onClick={() => {
|
||||
loadInitial();
|
||||
}}
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
padding: "6px 14px",
|
||||
borderRadius: 14,
|
||||
@ -619,6 +623,7 @@ export function MobileChat({
|
||||
type="button"
|
||||
onClick={() => removePendingFile(i)}
|
||||
aria-label={`Remove ${f.name}`}
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
border: "none",
|
||||
background: "transparent",
|
||||
@ -659,6 +664,7 @@ export function MobileChat({
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
disabled={!reachable || sending || uploading}
|
||||
aria-label="Attach"
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
@ -719,6 +725,7 @@ export function MobileChat({
|
||||
onClick={send}
|
||||
disabled={(!draft.trim() && pendingFiles.length === 0) || !reachable || sending || uploading}
|
||||
aria-label="Send"
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
|
||||
@ -218,6 +218,7 @@ export function MobileComms({ dark }: { dark: boolean }) {
|
||||
key={o.id}
|
||||
type="button"
|
||||
onClick={() => setFilter(o.id)}
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
|
||||
@ -83,11 +83,12 @@ export function MobileDetail({
|
||||
type="button"
|
||||
onClick={onBack}
|
||||
aria-label="Back"
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={iconButtonStyle(p, dark)}
|
||||
>
|
||||
{Icons.back({ size: 18 })}
|
||||
</button>
|
||||
<button type="button" aria-label="More" style={iconButtonStyle(p, dark)}>
|
||||
<button type="button" aria-label="More" className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none" style={iconButtonStyle(p, dark)}>
|
||||
{Icons.more({ size: 18 })}
|
||||
</button>
|
||||
</div>
|
||||
@ -183,6 +184,7 @@ export function MobileDetail({
|
||||
key={t.id}
|
||||
type="button"
|
||||
onClick={() => setTab(t.id)}
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
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:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 52,
|
||||
|
||||
@ -183,6 +183,7 @@ export function MobileHome({
|
||||
type="button"
|
||||
onClick={onSpawn}
|
||||
aria-label="Spawn new agent"
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: 24,
|
||||
|
||||
@ -83,6 +83,7 @@ export function MobileMe({
|
||||
type="button"
|
||||
onClick={() => setAccent(c)}
|
||||
aria-label={`Set accent ${c}`}
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
@ -173,6 +174,7 @@ function SegmentedRow({
|
||||
key={o.id}
|
||||
type="button"
|
||||
onClick={() => onChange(o.id)}
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
flex: 1,
|
||||
padding: "10px 8px",
|
||||
|
||||
@ -148,6 +148,7 @@ export function MobileSpawn({ dark, onClose }: { dark: boolean; onClose: () => v
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
aria-label="Close"
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
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:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
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:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
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:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 52,
|
||||
|
||||
@ -292,6 +292,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:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
@ -445,6 +446,7 @@ export function FilterChips({
|
||||
type="button"
|
||||
aria-checked={on}
|
||||
onClick={() => onChange(o.id)}
|
||||
className="focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user