From 7e03d33be05b8de36a1cab8747a5a6733d20e280 Mon Sep 17 00:00:00 2001 From: daproclaima Date: Thu, 18 Jul 2024 17:21:45 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=B8(frontend)=20improve=20keyboard=20n?= =?UTF-8?q?avigation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add css rules to highlight focused-visible navigable elements - update drop down components to make it keyboard navigable - add e2e keyboard navigation tests asserting it navigates through all focusable elements from top to bottom on groups index view when one group exists --- .../apps/desk/src/components/DropButton.tsx | 42 ++++++--- .../desk/src/cunningham/cunningham-style.css | 21 ++++- .../src/features/language/LanguagePicker.tsx | 5 ++ .../components/panel/PanelItem.tsx | 2 +- .../apps/desk/src/features/menu/MenuItems.tsx | 10 ++- .../components/CardCreateTeam.tsx | 4 +- .../teams-panel/components/PanelActions.tsx | 1 + .../apps/desk/src/pages/teams/index.tsx | 2 +- .../app-desk/keyboard-navigation.spec.ts | 86 +++++++++++++++++++ 9 files changed, 157 insertions(+), 16 deletions(-) create mode 100644 src/frontend/apps/e2e/__tests__/app-desk/keyboard-navigation.spec.ts diff --git a/src/frontend/apps/desk/src/components/DropButton.tsx b/src/frontend/apps/desk/src/components/DropButton.tsx index f79b78e..2b81887 100644 --- a/src/frontend/apps/desk/src/components/DropButton.tsx +++ b/src/frontend/apps/desk/src/components/DropButton.tsx @@ -2,10 +2,11 @@ import React, { PropsWithChildren, ReactNode, useEffect, + useRef, useState, } from 'react'; import { Button, DialogTrigger, Popover } from 'react-aria-components'; -import styled from 'styled-components'; +import styled, { createGlobalStyle } from 'styled-components'; const StyledPopover = styled(Popover)` background-color: white; @@ -29,6 +30,12 @@ const StyledButton = styled(Button)` text-wrap: nowrap; `; +const GlobalStyle = createGlobalStyle` + &:focus-visible { + outline: none; + } +`; + interface DropButtonProps { button: ReactNode; isOpen?: boolean; @@ -44,10 +51,18 @@ export const DropButton = ({ const [opacity, setOpacity] = useState(false); const [isLocalOpen, setIsLocalOpen] = useState(isOpen); + const ref = useRef(null); + useEffect(() => { setIsLocalOpen(isOpen); }, [isOpen]); + useEffect(() => { + if (ref.current) { + ref.current[isLocalOpen ? 'focus' : 'blur'](); + } + }, [isLocalOpen]); + const onOpenChangeHandler = (isOpen: boolean) => { setIsLocalOpen(isOpen); onOpenChange?.(isOpen); @@ -57,15 +72,20 @@ export const DropButton = ({ }; return ( - - {button} - - {children} - - + <> + + + {button} + +
+ {children} +
+
+
+ ); }; diff --git a/src/frontend/apps/desk/src/cunningham/cunningham-style.css b/src/frontend/apps/desk/src/cunningham/cunningham-style.css index 97c1ea3..5b5d147 100644 --- a/src/frontend/apps/desk/src/cunningham/cunningham-style.css +++ b/src/frontend/apps/desk/src/cunningham/cunningham-style.css @@ -5,6 +5,15 @@ @import url('./cunningham-custom-tokens.css'); @import url('../assets/fonts/Marianne/Marianne-font.css'); +a:focus-visible, +button:focus-visible, +.c__button:focus-visible, +.c__select__wrapper:focus-visible, +.c__datagrid__header:focus-visible { + outline: var(--c--theme--colors--primary-600) solid 2px; + border-radius: var(--c--components--button--border-radius--focus); +} + .c__input, .c__field, .c__select, @@ -314,6 +323,10 @@ input:-webkit-autofill:focus { transition: all 0.8s ease-in-out; } +.c__radio input:focus-visible { + outline: var(--c--theme--colors--primary-600) solid 2px; +} + /** * Button */ @@ -340,7 +353,8 @@ input:-webkit-autofill:focus { var(--c--theme--spacings--s); } -.c__button--primary { +.c__button--primary, +.c__button--primary:focus-visible { background-color: var(--c--components--button--primary--background--color); color: var(--c--components--button--primary--color); } @@ -470,6 +484,11 @@ input:-webkit-autofill:focus { /** * Modal */ +.c__modal:focus-visible { + outline: none; + box-shadow: none; +} + .c__modal__backdrop { z-index: 1000; } diff --git a/src/frontend/apps/desk/src/features/language/LanguagePicker.tsx b/src/frontend/apps/desk/src/features/language/LanguagePicker.tsx index 990cd77..feafcd1 100644 --- a/src/frontend/apps/desk/src/features/language/LanguagePicker.tsx +++ b/src/frontend/apps/desk/src/features/language/LanguagePicker.tsx @@ -30,6 +30,11 @@ const SelectStyled = styled(Select)<{ $isSmall?: boolean }>` &:hover { border-color: var(--c--theme--colors--primary-500); } + + .c__button--tertiary-text:focus-visible { + outline: var(--c--theme--colors--primary-600) solid 2px; + border-radius: var(--c--components--button--border-radius--focus); + } } `; diff --git a/src/frontend/apps/desk/src/features/mail-domains/components/panel/PanelItem.tsx b/src/frontend/apps/desk/src/features/mail-domains/components/panel/PanelItem.tsx index c9db2e4..442252c 100644 --- a/src/frontend/apps/desk/src/features/mail-domains/components/panel/PanelItem.tsx +++ b/src/frontend/apps/desk/src/features/mail-domains/components/panel/PanelItem.tsx @@ -41,7 +41,7 @@ export const PanelMailDomains = ({ mailDomain }: MailDomainProps) => { return ( { onMouseOver={() => setIsTooltipOpen(true)} onMouseLeave={() => setIsTooltipOpen(false)} style={{ display: 'block' }} + $css={` + &:focus-visible { + outline: #fff solid 2px; + }`} > { $background={background} $radius="10px" > - + { - +