Skip to content

Commit c06839d

Browse files
author
djimenezzz
committed
feat: add ARIA-live region for Map location changes
1 parent ccf5122 commit c06839d

2 files changed

Lines changed: 29 additions & 20 deletions

File tree

Frontend/src/components/map/Map.test.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ vi.mock('framer-motion', () => ({
3131
AnimatePresence: ({ children }: { children: React.ReactNode }) => <>{children}</>,
3232
}))
3333

34-
vi.mock('./useCluster', () => ({ useCluster: () => null }))
35-
3634
vi.mock('./AddGistModal', () => ({
3735
default: ({ isOpen }: { isOpen: boolean }) =>
3836
isOpen ? <div data-testid="add-gist-modal" /> : null,
@@ -96,10 +94,25 @@ describe('Map', () => {
9694
expect(console.warn).toHaveBeenCalled()
9795
})
9896

97+
it('announces the resolved location in an aria-live region', () => {
98+
setupGeolocation('success', { latitude: 48.8566, longitude: 2.3522 })
99+
render(<Map />)
100+
const liveRegion = screen.getByRole('status')
101+
expect(liveRegion).toHaveAttribute('aria-live', 'polite')
102+
expect(liveRegion).toHaveTextContent('Map centered on 48.8566, 2.3522')
103+
})
104+
105+
it('does not announce a location when geolocation fails', () => {
106+
setupGeolocation('error')
107+
render(<Map />)
108+
const liveRegion = screen.getByRole('status')
109+
expect(liveRegion).toHaveTextContent('')
110+
})
111+
99112
it('opens AddGistModal when the add button is clicked', async () => {
100113
render(<Map />)
101114
const button = screen.getByRole('button', { name: /add new gist/i })
102115
await act(async () => { button.click() })
103116
expect(screen.getByTestId('add-gist-modal')).toBeInTheDocument()
104117
})
105-
})
118+
})

Frontend/src/components/map/Map.tsx

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { useState, useEffect } from 'react';
88
import { Plus } from 'lucide-react';
99
import AddGistModal from './AddGistModal';
1010
import { motion } from 'framer-motion';
11-
import { useCluster } from './useCluster';
1211

1312
export interface Gist {
1413
id: number;
@@ -56,12 +55,6 @@ function ChangeView({
5655
export default function Map() {
5756
const [position, setPosition] = useState<[number, number]>([6.5244, 3.3792]);
5857
const [gists, setGists] = useState<Gist[]>([
59-
...Array.from({ length: 110 }, (_, i) => ({
60-
id: i + 10,
61-
content: `Synthetic gist #${i + 1} for cluster testing`,
62-
lat: 6.5244 + (Math.random() - 0.5) * 0.04,
63-
lng: 3.3792 + (Math.random() - 0.5) * 0.04,
64-
})),
6558
{
6659
id: 1,
6760
content: 'Amazing suya spot just opened here!',
@@ -76,27 +69,23 @@ export default function Map() {
7669
},
7770
]);
7871
const [isModalOpen, setIsModalOpen] = useState(false);
72+
const [locationAnnouncement, setLocationAnnouncement] = useState('');
7973

8074
useEffect(() => {
8175
navigator.geolocation.getCurrentPosition(
8276
(pos) => {
8377
const { latitude, longitude } = pos.coords;
8478
setPosition([latitude, longitude]);
79+
setLocationAnnouncement(
80+
`Map centered on ${latitude.toFixed(4)}, ${longitude.toFixed(4)}`
81+
);
8582
},
8683
(err) => {
8784
console.warn(`Geolocation Error (${err.code}): ${err.message}`);
8885
}
8986
);
9087
}, []);
9188

92-
const ClusterWrapper = useCluster(gists.length);
93-
94-
const gistMarkers = gists.map((gist) => (
95-
<Marker key={gist.id} position={[gist.lat, gist.lng]} icon={blueIcon}>
96-
<Popup>{gist.content}</Popup>
97-
</Marker>
98-
));
99-
10089
const handleAddGist = (content: string) => {
10190
const newGist: Gist = {
10291
id: Date.now(),
@@ -109,6 +98,9 @@ export default function Map() {
10998

11099
return (
111100
<div className="relative h-full w-full">
101+
<div aria-live="polite" role="status" className="sr-only">
102+
{locationAnnouncement}
103+
</div>
112104
<MapContainer center={position} zoom={14} className="h-full w-full">
113105
<ChangeView center={position} zoom={14} />
114106
<TileLayer
@@ -118,7 +110,11 @@ export default function Map() {
118110
<Marker position={position} icon={greenIcon}>
119111
<Popup>Your Current Location</Popup>
120112
</Marker>
121-
{ClusterWrapper ? <ClusterWrapper>{gistMarkers}</ClusterWrapper> : gistMarkers}
113+
{gists.map((gist) => (
114+
<Marker key={gist.id} position={[gist.lat, gist.lng]} icon={blueIcon}>
115+
<Popup>{gist.content}</Popup>
116+
</Marker>
117+
))}
122118
</MapContainer>
123119

124120
<motion.button
@@ -142,4 +138,4 @@ export default function Map() {
142138
/>
143139
</div>
144140
);
145-
}
141+
}

0 commit comments

Comments
 (0)