Skip to content

Commit b6190e1

Browse files
committed
Announce page changes via aria-live
1 parent 19ba64c commit b6190e1

File tree

8 files changed

+48
-13
lines changed

8 files changed

+48
-13
lines changed

services/backend-api/client/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import advancedFormat from "dayjs/plugin/advancedFormat";
1010
import dayjs from "dayjs";
1111
import { SendTestArticleProvider } from "./contexts";
1212
import Pages from "./pages";
13+
import { AccessibleNavigationAnnouncer } from "./components/AccessibleNavigationAnnouncer";
1314

1415
dayjs.extend(utc);
1516
dayjs.extend(timezone);
@@ -20,6 +21,7 @@ dayjs.extend(relativeTime);
2021
const App: React.FC = () => {
2122
return (
2223
<Box display="flex" flexDir="column" height="100vh" className="he">
24+
<AccessibleNavigationAnnouncer />
2325
<SendTestArticleProvider>
2426
<Pages />
2527
</SendTestArticleProvider>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React, { useState, useEffect } from "react";
2+
import { useLocation } from "react-router-dom";
3+
import { chakra } from "@chakra-ui/react";
4+
5+
export const AccessibleNavigationAnnouncer = () => {
6+
// the message that will be announced
7+
const [message, setMessage] = useState("");
8+
// get location from router
9+
const location = useLocation();
10+
11+
// only run this when location change (note the dependency [location])
12+
useEffect(() => {
13+
// ignore the /
14+
if (location.pathname.slice(1)) {
15+
// make sure navigation has occurred and screen reader is ready
16+
setTimeout(() => setMessage(`Navigated to ${location.pathname.slice(1)} page.`), 500);
17+
} else {
18+
// just ignore the / route
19+
setMessage("");
20+
}
21+
}, [location]);
22+
23+
return (
24+
<chakra.span srOnly role="status" aria-live="polite" aria-atomic="true">
25+
{message}
26+
</chakra.span>
27+
);
28+
};

services/backend-api/client/src/components/NewHeader/index.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,8 @@ export const NewHeader = ({ invertBackground }: Props) => {
5656
<HStack overflow="hidden" gap={8}>
5757
<Flex alignItems="center" overflow="hidden">
5858
{discordBotData && (
59-
<Link to={pages.userFeeds()}>
60-
<Flex
61-
alignItems="center"
62-
paddingBottom="1"
63-
overflow="hidden"
64-
as="a"
65-
href="/"
66-
aria-label="MonitoRSS Home"
67-
>
59+
<Link to={pages.userFeeds()} aria-label="MonitoRSS Home">
60+
<Flex alignItems="center" paddingBottom="1" overflow="hidden">
6861
<Avatar
6962
src={discordBotData.result.avatar || undefined}
7063
size="sm"

services/backend-api/client/src/features/feed/components/UserFeedsTable/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ export const UserFeedsTable: React.FC<Props> = ({ onSelectedFeedId }) => {
445445
<form
446446
hidden={isInitiallyLoading}
447447
id="user-feed-search"
448+
role="search"
448449
onSubmit={(e) => {
449450
e.preventDefault();
450451
onSearchSubmit();

services/backend-api/client/src/mocks/data/discordBot.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const mockDiscordBot: DiscordBot = {
44
id: "1",
55
username: "Discord Bot".padEnd(1000, "hi"),
66
avatar: "https://via.placeholder.com/140x100",
7-
inviteLink: ''
7+
inviteLink: "https://www.google.com",
88
};
99

1010
export default mockDiscordBot;

services/backend-api/client/src/mocks/data/userFeeds.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ const mockUserFeeds: UserFeed[] = [
306306
},
307307
],
308308
healthStatus: UserFeedHealthStatus.Ok,
309-
disabledCode: UserFeedDisabledCode.FeedTooLarge,
309+
disabledCode: undefined,
310310
refreshRateSeconds: 60,
311311
userRefreshRateSeconds: 120,
312312
},

services/backend-api/client/src/mocks/handlers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ const handlers = [
724724
ctx.json<GetUserFeedRequestsOutput>({
725725
result: {
726726
requests: mockUserFeedRequests,
727-
nextRetryTimestamp: Math.floor(new Date(2020).getTime() / 1000),
727+
nextRetryTimestamp: null,
728728
feedHostGlobalRateLimit: null,
729729
},
730730
})

services/backend-api/client/src/pages/UserFeed.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export const UserFeed: React.FC = () => {
9696
const { search: urlSearch } = useLocation();
9797
const { isOpen, onClose, onOpen } = useDisclosure();
9898
const menuButtonRef = useRef<HTMLButtonElement>(null);
99+
const feedsBreadcrumbLinkRef = useRef<HTMLAnchorElement>(null);
99100
const [addConnectionType, setAddConnectionType] = useState<
100101
{ type: "discord-channel" | "discord-webhook"; isChannelThread?: boolean } | undefined
101102
>(undefined);
@@ -138,6 +139,12 @@ export const UserFeed: React.FC = () => {
138139
}
139140
}, [feedTitle]);
140141

142+
useEffect(() => {
143+
if (feedsBreadcrumbLinkRef.current) {
144+
feedsBreadcrumbLinkRef.current?.focus();
145+
}
146+
}, [feedsBreadcrumbLinkRef.current]);
147+
141148
const isAtLimit = dailyLimit ? dailyLimit.current >= dailyLimit.max : false;
142149

143150
const onDeleteFeed = async () => {
@@ -279,7 +286,11 @@ export const UserFeed: React.FC = () => {
279286
<Stack flex={1}>
280287
<Breadcrumb>
281288
<BreadcrumbItem>
282-
<BreadcrumbLink as={RouterLink} to={pages.userFeeds()}>
289+
<BreadcrumbLink
290+
ref={feedsBreadcrumbLinkRef}
291+
as={RouterLink}
292+
to={pages.userFeeds()}
293+
>
283294
Feeds
284295
</BreadcrumbLink>
285296
</BreadcrumbItem>

0 commit comments

Comments
 (0)