fix(map): announce the places filter control as opening a dialog

MapTogglePill always set aria-pressed, so the phone map's Filters control read
as a toggle although it opens a sheet. An opensDialog option drops aria-pressed
for aria-haspopup="dialog"; the other map toggles are unchanged.
This commit is contained in:
EvKoh
2026-10-03 15:50:30 +02:00
committed by Maurice
parent a9f7adf99b
commit 3951e8cc9a
3 changed files with 18 additions and 5 deletions
+9 -2
View File
@@ -6,7 +6,7 @@ import { MAP_CONTROL_SHADOW } from './mapControlShadow'
* One round on/off control in the frosted shell every map control wears, so a new
* one lines up with the compass, the layer switcher and the overview toggle.
*/
export function MapTogglePill({ active, onToggle, label, icon, testId, tooltipPlacement = 'left', badge = 0 }: {
export function MapTogglePill({ active, onToggle, label, icon, testId, tooltipPlacement = 'left', badge = 0, opensDialog = false }: {
active: boolean
onToggle: () => void
label: string
@@ -16,6 +16,12 @@ export function MapTogglePill({ active, onToggle, label, icon, testId, tooltipPl
tooltipPlacement?: 'left' | 'right'
/** A count pinned to the top right corner while above zero (how many filters are on, say). */
badge?: number
/**
* The control opens a dialog instead of switching something on and off (the phone
* map's places filter): it then announces the dialog, not a pressed state it
* does not have. `active` still lights it.
*/
opensDialog?: boolean
}) {
return (
<div style={{
@@ -33,7 +39,8 @@ export function MapTogglePill({ active, onToggle, label, icon, testId, tooltipPl
type="button"
onClick={onToggle}
aria-label={label}
aria-pressed={active}
aria-pressed={opensDialog ? undefined : active}
aria-haspopup={opensDialog ? 'dialog' : undefined}
data-testid={testId}
className={active ? 'text-accent' : 'text-content-muted'}
style={{
@@ -7,7 +7,8 @@ import { useTranslation } from '../../../../i18n'
/**
* The phone map's way into the places filter: a round control in the right-hand
* stack, lit and badged with how many filters are narrowing the markers. The sheet
* it opens is the shell's 'placesFilter' sheet.
* it opens is the shell's 'placesFilter' sheet, so the button announces a dialog
* rather than a pressed state.
*/
export function MPlacesFilterPill({ onOpen }: { onOpen: () => void }) {
const { t } = useTranslation()
@@ -23,6 +24,7 @@ export function MPlacesFilterPill({ onOpen }: { onOpen: () => void }) {
label={label}
badge={count}
testId="places-filter-pill"
opensDialog
icon={<SlidersHorizontal size={17} strokeWidth={2} />}
/>
)
@@ -958,7 +958,9 @@ describe('MMapArea — places filter', () => {
const { shell } = renderArea({ trTab: 'plan' })
const pill = screen.getByTestId('places-filter-pill')
expect(pill).toHaveAccessibleName('Filters')
expect(pill).toHaveAttribute('aria-pressed', 'false')
// It opens a sheet: a dialog to announce, not an on/off state.
expect(pill).toHaveAttribute('aria-haspopup', 'dialog')
expect(pill).not.toHaveAttribute('aria-pressed')
act(() => { pill.click() })
expect(shell.openSheet).toHaveBeenCalledWith('placesFilter')
})
@@ -967,7 +969,9 @@ describe('MMapArea — places filter', () => {
seedStore(useTripStore, { placesFilter: 'unplanned', placesRatingFilter: 4 })
renderArea({ trTab: 'plan' })
const pill = screen.getByTestId('places-filter-pill')
expect(pill).toHaveAttribute('aria-pressed', 'true')
expect(pill).toHaveClass('text-accent')
expect(pill).not.toHaveAttribute('aria-pressed')
expect(pill).toHaveAttribute('aria-haspopup', 'dialog')
expect(pill).toHaveAccessibleName('Filters (2)')
expect(screen.getByText('2')).toHaveAttribute('aria-hidden', 'true')
})