Skip to content

Commit 462cb1c

Browse files
committed
feat(a11y): unify dock icon, highlight all elements on severity hover
- Use i-ph-person-simple-circle-duotone as the single a11y icon everywhere (dock definition, panel brand, and the playground rail/header). - Hovering (or focusing) a summary severity chip now previews every element of that impact in the page, restoring the selection highlight on leave. Co-authored-with an agent.
1 parent 143c6ec commit 462cb1c

7 files changed

Lines changed: 38 additions & 8 deletions

File tree

examples/a11y-messages-playground/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
<div class="h-full flex flex-col">
3636
<header class="shrink-0 flex items-center gap-3 h-nav px-3 border-b border-base bg-base">
3737
<h1 class="m0 flex items-center gap-1.5 shrink-0 text-sm font-semibold select-none">
38-
<span class="i-ph-wheelchair-duotone text-base color-active"></span>
38+
<span class="i-ph-person-simple-circle-duotone text-base color-active"></span>
3939
<span>A11y × Messages Playground</span>
4040
</h1>
4141
<p id="status" class="m0 text-xs font-mono op-fade"><span id="conn">Connecting…</span></p>

examples/a11y-messages-playground/src/client/icons.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// the offline Phosphor set renders without a runtime icon library. UnoCSS only
44
// emits classes it can see in source, hence the literal map.
55
const ICONS: Record<string, string> = {
6-
'ph:wheelchair-duotone': 'i-ph-wheelchair-duotone',
6+
'ph:person-simple-circle-duotone': 'i-ph-person-simple-circle-duotone',
77
'ph:notification-duotone': 'i-ph-notification-duotone',
88
}
99

plugins/a11y/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export function createA11yDevframe(options: A11yDevframeOptions = {}): DevframeD
8080
packageName: pkg.name,
8181
homepage: pkg.homepage,
8282
description: pkg.description,
83-
icon: options.icon ?? 'ph:wheelchair-duotone',
83+
icon: options.icon ?? 'ph:person-simple-circle-duotone',
8484
basePath: options.basePath ?? BASE_PATH,
8585
cli: {
8686
command: id,

plugins/a11y/src/spa/app.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ export function App() {
3131
// and the "Generate fix prompts" dialog.
3232
const [selected, setSelected] = createSignal<Set<string>>(new Set())
3333
const [dialogOpen, setDialogOpen] = createSignal(false)
34+
// Transient severity preview: hovering a summary chip lights up every element
35+
// of that impact, overriding the selection highlight until the hover ends.
36+
const [hoverImpact, setHoverImpact] = createSignal<Impact | null>(null)
3437

3538
const storedAuto = (() => {
3639
try {
@@ -109,6 +112,20 @@ export function App() {
109112
return out
110113
})
111114

115+
// Every element of a given impact (across routes), for the chip-hover preview.
116+
const impactPins = (impact: Impact): PinTarget[] => {
117+
const out: PinTarget[] = []
118+
for (const report of routes()) {
119+
for (const v of report.violations) {
120+
if (includeViolation(v) && v.impact === impact) {
121+
for (const node of v.nodes)
122+
out.push(nodePin(v, node))
123+
}
124+
}
125+
}
126+
return out
127+
}
128+
112129
const selectedItems = createMemo<SelectedItem[]>(() => {
113130
const sel = selected()
114131
const out: SelectedItem[] = []
@@ -170,8 +187,12 @@ export function App() {
170187
setExpandedRoutes(prev => (prev.has(r) ? prev : new Set(prev).add(r)))
171188
})
172189

173-
// Push the highlight set (derived from the selection) to the in-page agent.
174-
createEffect(() => channel.setPins(selectedPins()))
190+
// Push the highlight set to the in-page agent: the hovered impact's elements
191+
// while a summary chip is hovered, otherwise the selection.
192+
createEffect(() => {
193+
const hov = hoverImpact()
194+
channel.setPins(hov ? impactPins(hov) : selectedPins())
195+
})
175196

176197
// defaultHighlight: select all of a route's violations the first time it's scanned.
177198
const highlighted = new Set<string>()
@@ -309,6 +330,7 @@ export function App() {
309330
counts={chipCounts()}
310331
filter={filter()}
311332
onToggleFilter={toggleFilter}
333+
onHoverImpact={setHoverImpact}
312334
totalNodes={totalNodes()}
313335
totalRules={totalRules()}
314336
routeCount={routes().length}

plugins/a11y/src/spa/components/header.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export function Header(props: HeaderProps) {
2424
return (
2525
<header class={nav()}>
2626
<span class={navBrand()}>
27-
<span aria-hidden class="i-ph-person-arms-spread-duotone text-base color-active" />
27+
<span aria-hidden class="i-ph-person-simple-circle-duotone text-base color-active" />
2828
<span>A11y Inspector</span>
2929
</span>
3030
<span class="flex-1" />
@@ -96,6 +96,8 @@ interface SummaryProps {
9696
counts: Record<Impact, number>
9797
active: Impact | null
9898
onToggle: (impact: Impact) => void
99+
/** Hover/focus a chip to preview every element of that impact in the page. */
100+
onHover?: (impact: Impact | null) => void
99101
}
100102

101103
/** The severity summary chips — also serve as the impact filter. */
@@ -111,8 +113,12 @@ export function Summary(props: SummaryProps) {
111113
class={`chip${count() === 0 ? ' chip--zero' : ''}`}
112114
style={{ '--impact': IMPACT_COLOR[impact] }}
113115
aria-pressed={props.active === impact}
114-
aria-label={`${count()} ${IMPACT_LABEL[impact]} issues — filter`}
116+
aria-label={`${count()} ${IMPACT_LABEL[impact]} issues — filter and highlight`}
115117
onClick={() => props.onToggle(impact)}
118+
onMouseEnter={() => props.onHover?.(impact)}
119+
onMouseLeave={() => props.onHover?.(null)}
120+
onFocus={() => props.onHover?.(impact)}
121+
onBlur={() => props.onHover?.(null)}
116122
>
117123
<span class="chip__count">{count()}</span>
118124
<span class="chip__label">{IMPACT_LABEL[impact]}</span>

plugins/a11y/src/spa/components/summary-bar.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const base = {
1919
counts: { critical: 3, serious: 5, moderate: 2, minor: 8 },
2020
filter: null,
2121
onToggleFilter: noop,
22+
onHoverImpact: noop,
2223
totalNodes: 18,
2324
totalRules: 7,
2425
routeCount: 3,

plugins/a11y/src/spa/components/summary.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ interface SummaryBarProps {
55
counts: Record<Impact, number>
66
filter: Impact | null
77
onToggleFilter: (impact: Impact) => void
8+
onHoverImpact: (impact: Impact | null) => void
89
totalNodes: number
910
totalRules: number
1011
routeCount: number
@@ -23,7 +24,7 @@ interface SummaryBarProps {
2324
export function SummaryBar(props: SummaryBarProps) {
2425
return (
2526
<div class="summary-bar">
26-
<Summary counts={props.counts} active={props.filter} onToggle={props.onToggleFilter} />
27+
<Summary counts={props.counts} active={props.filter} onToggle={props.onToggleFilter} onHover={props.onHoverImpact} />
2728

2829
<div class="summary-bar__toolbar">
2930
<span class="summary-bar__stat">

0 commit comments

Comments
 (0)