From b6323668ec3fa90904790fd40c7ec7ac4228ce66 Mon Sep 17 00:00:00 2001 From: Simo Date: Tue, 7 Oct 2025 15:01:39 +0200 Subject: [PATCH 1/3] fix: improve GroupCard keyboard accessibility Signed-off-by: Simo --- .../groups/page/list/card/GroupCard.test.tsx | 20 ++++++++++++-- .../groups/page/list/card/GroupCard.tsx | 27 +++++++++++++++---- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/__tests__/components/groups/page/list/card/GroupCard.test.tsx b/__tests__/components/groups/page/list/card/GroupCard.test.tsx index bf776d8c45..a88731face 100644 --- a/__tests__/components/groups/page/list/card/GroupCard.test.tsx +++ b/__tests__/components/groups/page/list/card/GroupCard.test.tsx @@ -30,6 +30,10 @@ jest.mock( const push = jest.fn(); (useRouter as jest.Mock).mockReturnValue({ push }); +beforeEach(() => { + push.mockClear(); +}); + describe("GroupCard", () => { const group: any = { id: "g1", @@ -61,8 +65,20 @@ describe("GroupCard", () => { } it("navigates to community view when idle", () => { - renderComp(); - fireEvent.click(document.querySelector("div.tw-col-span-1")!); + const { getByRole } = renderComp(); + fireEvent.click(getByRole("button")); + expect(push).toHaveBeenCalledWith(`/network?page=1&group=${group.id}`); + }); + + it("navigates to community view when pressing Enter", () => { + const { getByRole } = renderComp(); + fireEvent.keyDown(getByRole("button"), { key: "Enter" }); + expect(push).toHaveBeenCalledWith(`/network?page=1&group=${group.id}`); + }); + + it("navigates to community view when pressing Space", () => { + const { getByRole } = renderComp(); + fireEvent.keyDown(getByRole("button"), { key: " " }); expect(push).toHaveBeenCalledWith(`/network?page=1&group=${group.id}`); }); diff --git a/components/groups/page/list/card/GroupCard.tsx b/components/groups/page/list/card/GroupCard.tsx index f0ddd731ad..31c2369c29 100644 --- a/components/groups/page/list/card/GroupCard.tsx +++ b/components/groups/page/list/card/GroupCard.tsx @@ -1,6 +1,12 @@ "use client"; -import { useContext, useEffect, useState, type JSX } from "react"; +import { + useContext, + useEffect, + useState, + type JSX, + type KeyboardEvent, +} from "react"; import { ApiGroupFull } from "@/generated/models/ApiGroupFull"; import { getRandomColorWithSeed } from "@/helpers/Helpers"; import GroupCardView from "./GroupCardView"; @@ -110,12 +116,23 @@ export default function GroupCard({ router.push(`/network?page=1&group=${group?.id}`); }; + const onCardKeyDown = (event: KeyboardEvent) => { + if (event.key === "Enter" || event.key === " ") { + event.preventDefault(); + goToCommunityView(); + } + }; + + const isIdle = state === GroupCardState.IDLE; + return (
+ role="button" + tabIndex={isIdle ? 0 : -1} + aria-disabled={!isIdle} + className={`${isIdle && "tw-group tw-cursor-pointer"} tw-col-span-1`} + onClick={goToCommunityView} + onKeyDown={onCardKeyDown}>
Date: Tue, 7 Oct 2025 15:39:24 +0200 Subject: [PATCH 2/3] wip Signed-off-by: Simo --- .../groups/page/list/card/GroupCard.tsx | 63 ++++++++----------- .../page/list/card/GroupCardConfigs.tsx | 4 +- .../page/list/card/GroupCardContent.tsx | 4 +- .../groups/page/list/card/GroupCardHeader.tsx | 2 +- .../card/actions/GroupCardEditActions.tsx | 2 +- 5 files changed, 31 insertions(+), 44 deletions(-) diff --git a/components/groups/page/list/card/GroupCard.tsx b/components/groups/page/list/card/GroupCard.tsx index 31c2369c29..b12fab8371 100644 --- a/components/groups/page/list/card/GroupCard.tsx +++ b/components/groups/page/list/card/GroupCard.tsx @@ -1,12 +1,6 @@ "use client"; -import { - useContext, - useEffect, - useState, - type JSX, - type KeyboardEvent, -} from "react"; +import { useContext, useEffect, useState, type JSX } from "react"; import { ApiGroupFull } from "@/generated/models/ApiGroupFull"; import { getRandomColorWithSeed } from "@/helpers/Helpers"; import GroupCardView from "./GroupCardView"; @@ -111,40 +105,33 @@ export default function GroupCard({ ), }; - const goToCommunityView = () => { - if (state !== GroupCardState.IDLE) return; - router.push(`/network?page=1&group=${group?.id}`); - }; - - const onCardKeyDown = (event: KeyboardEvent) => { - if (event.key === "Enter" || event.key === " ") { - event.preventDefault(); - goToCommunityView(); - } - }; - const isIdle = state === GroupCardState.IDLE; + const cardLabel = + group?.name ?? titlePlaceholder ?? "View community group details"; return ( -
-
-
-
-
- {components[state]} +
+ {isIdle && ( + + )} +
+
+
+
+
+ {components[state]} +
); diff --git a/components/groups/page/list/card/GroupCardConfigs.tsx b/components/groups/page/list/card/GroupCardConfigs.tsx index 4db0505683..cf7a4001c8 100644 --- a/components/groups/page/list/card/GroupCardConfigs.tsx +++ b/components/groups/page/list/card/GroupCardConfigs.tsx @@ -203,7 +203,7 @@ export default function GroupCardConfigs({ scrollContainer("left"); }} aria-label="Scroll left" - className="tw-inline-flex tw-items-center tw-justify-center tw-group tw-absolute tw-top-0.5 tw-z-[5] tw-p-0 tw-h-7 tw-w-7 tw-left-0 tw-bg-iron-900 hover:tw-bg-iron-800 tw-ring-1 tw-ring-inset tw-ring-iron-650 tw-rounded-md tw-border-none tw-transition tw-duration-300 tw-ease-out"> + className="tw-inline-flex tw-items-center tw-justify-center tw-group tw-absolute tw-top-0.5 tw-z-[20] tw-p-0 tw-h-7 tw-w-7 tw-left-0 tw-bg-iron-900 hover:tw-bg-iron-800 tw-ring-1 tw-ring-inset tw-ring-iron-650 tw-rounded-md tw-border-none tw-transition tw-duration-300 tw-ease-out"> + className="tw-inline-flex tw-items-center tw-justify-center tw-group tw-absolute tw-top-0.5 tw-z-[20] tw-p-0 tw-h-7 tw-w-7 tw-right-0 tw-bg-iron-900 hover:tw-bg-iron-800 tw-ring-1 tw-ring-inset tw-ring-iron-650 tw-rounded-md tw-border-none tw-transition tw-duration-300 tw-ease-out"> + } tw-relative tw-z-20 tw-whitespace-nowrap tw-inline-flex tw-items-center tw-bg-iron-800 tw-border tw-border-solid tw-rounded-lg tw-px-3 tw-py-2 tw-text-sm tw-font-semibold tw-shadow-sm focus-visible:tw-outline focus-visible:tw-outline-2 focus-visible:tw-outline-offset-2 focus-visible:tw-outline-iron-700 tw-transition tw-duration-300 tw-ease-out`}> Rep all
diff --git a/components/groups/page/list/card/GroupCardHeader.tsx b/components/groups/page/list/card/GroupCardHeader.tsx index 678e8ddeaf..1d80d031a6 100644 --- a/components/groups/page/list/card/GroupCardHeader.tsx +++ b/components/groups/page/list/card/GroupCardHeader.tsx @@ -49,7 +49,7 @@ export default function GroupCardHeader({ ? `/${group?.created_by.handle ?? userPlaceholder}` : userPlaceholder ?? "" } - className="tw-no-underline hover:tw-underline tw-transition tw-duration-300 tw-ease-out tw-text-iron-50 hover:tw-text-iron-400"> + className="tw-relative tw-z-20 tw-no-underline hover:tw-underline tw-transition tw-duration-300 tw-ease-out tw-text-iron-50 hover:tw-text-iron-400"> {group?.created_by.handle ?? userPlaceholder} diff --git a/components/groups/page/list/card/actions/GroupCardEditActions.tsx b/components/groups/page/list/card/actions/GroupCardEditActions.tsx index cb9a2775be..26aec83495 100644 --- a/components/groups/page/list/card/actions/GroupCardEditActions.tsx +++ b/components/groups/page/list/card/actions/GroupCardEditActions.tsx @@ -40,7 +40,7 @@ export default function GroupCardEditActions({ useEffect(() => setEditTitle(getEditTitle()), [isMyFilter]); return ( -
+