From 146ff4f3dfd6e9debb1d28ca72485734d1e08cf7 Mon Sep 17 00:00:00 2001 From: Kyzyl-ool Kezhik Date: Mon, 30 Oct 2023 20:09:39 +0100 Subject: [PATCH] feat: improving a11y (#1070) Co-authored-by: kkmch --- .../Dialog/ButtonClose/ButtonClose.tsx | 4 +++ src/components/Dialog/i18n/en.json | 3 +++ src/components/Dialog/i18n/index.ts | 8 ++++++ src/components/Dialog/i18n/ru.json | 3 +++ src/components/DropdownMenu/DropdownMenu.tsx | 1 + src/components/Link/Link.tsx | 11 +++++--- src/components/PersonaWrap/PersonaWrap.scss | 27 +++++++++++++++++++ src/components/PersonaWrap/PersonaWrap.tsx | 14 +++++----- src/components/index.ts | 1 + 9 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 src/components/Dialog/i18n/en.json create mode 100644 src/components/Dialog/i18n/index.ts create mode 100644 src/components/Dialog/i18n/ru.json diff --git a/src/components/Dialog/ButtonClose/ButtonClose.tsx b/src/components/Dialog/ButtonClose/ButtonClose.tsx index 30bd7b724d..cc4be549a5 100644 --- a/src/components/Dialog/ButtonClose/ButtonClose.tsx +++ b/src/components/Dialog/ButtonClose/ButtonClose.tsx @@ -5,6 +5,7 @@ import {Xmark} from '@gravity-ui/icons'; import {Button} from '../../Button'; import {Icon} from '../../Icon'; import {block} from '../../utils/cn'; +import i18n from '../i18n'; import './ButtonClose.scss'; @@ -25,6 +26,9 @@ export function ButtonClose({onClose}: ButtonCloseProps) { size="l" className={b('btn')} onClick={(event) => onClose(event, {isOutsideClick: false})} + extraProps={{ + 'aria-label': i18n('close'), + }} > diff --git a/src/components/Dialog/i18n/en.json b/src/components/Dialog/i18n/en.json new file mode 100644 index 0000000000..ab6f262280 --- /dev/null +++ b/src/components/Dialog/i18n/en.json @@ -0,0 +1,3 @@ +{ + "close": "Close dialog" +} diff --git a/src/components/Dialog/i18n/index.ts b/src/components/Dialog/i18n/index.ts new file mode 100644 index 0000000000..ff9d0b1505 --- /dev/null +++ b/src/components/Dialog/i18n/index.ts @@ -0,0 +1,8 @@ +import {addComponentKeysets} from '../../utils/addComponentKeysets'; + +import en from './en.json'; +import ru from './ru.json'; + +const COMPONENT = 'Dialog'; + +export default addComponentKeysets({en, ru}, COMPONENT); diff --git a/src/components/Dialog/i18n/ru.json b/src/components/Dialog/i18n/ru.json new file mode 100644 index 0000000000..a47c76ca5b --- /dev/null +++ b/src/components/Dialog/i18n/ru.json @@ -0,0 +1,3 @@ +{ + "close": "Закрыть диалоговое окно" +} diff --git a/src/components/DropdownMenu/DropdownMenu.tsx b/src/components/DropdownMenu/DropdownMenu.tsx index db45a3802d..302f8e73ee 100644 --- a/src/components/DropdownMenu/DropdownMenu.tsx +++ b/src/components/DropdownMenu/DropdownMenu.tsx @@ -137,6 +137,7 @@ const DropdownMenu = ({ return ( + {/*as this div has Button component as child, clicking on it one fires onClick of this div on bubbling*/} {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
(function Link( const commonProps = { title, - children, onClick, onClickCapture: handleClickCapture, onFocus, @@ -75,7 +74,6 @@ export const Link = React.forwardRef(function Link( const relProp = target === '_blank' && !rel ? 'noopener noreferrer' : rel; return ( - // eslint-disable-next-line jsx-a11y/anchor-has-content )} {...commonProps} @@ -83,7 +81,9 @@ export const Link = React.forwardRef(function Link( href={href} target={target} rel={relProp} - /> + > + {children} + ); } else { return ( @@ -91,9 +91,12 @@ export const Link = React.forwardRef(function Link( {...(extraProps as React.HTMLAttributes)} {...commonProps} ref={ref as React.Ref} + // as this element has onClick handler // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex tabIndex={0} - /> + > + {children} + ); } }); diff --git a/src/components/PersonaWrap/PersonaWrap.scss b/src/components/PersonaWrap/PersonaWrap.scss index f5779c6c04..1ccbafe1d3 100644 --- a/src/components/PersonaWrap/PersonaWrap.scss +++ b/src/components/PersonaWrap/PersonaWrap.scss @@ -57,14 +57,27 @@ $block: '.#{variables.$ns}persona'; } &__main { + @include mixins.button-reset(); + height: $avatarSize; display: inline-flex; align-items: center; padding-right: 6px; + border-radius: inherit; #{$block}_closeable & { padding-right: 0; } + #{$block}_clickable & { + outline-offset: -1px; + + &:focus { + outline: 2px solid var(--g-color-line-focus); + } + &:focus:not(:focus-visible) { + outline: 0; + } + } } &__avatar { @@ -120,6 +133,8 @@ $block: '.#{variables.$ns}persona'; } &__close { + @include mixins.button-reset(); + height: $avatarSize; width: 16px; display: inline-flex; @@ -128,6 +143,7 @@ $block: '.#{variables.$ns}persona'; cursor: pointer; padding-right: 6px; color: var(--g-color-text-secondary); + box-sizing: initial; transition-property: color; transition-duration: $transitionDuration; @@ -137,4 +153,15 @@ $block: '.#{variables.$ns}persona'; color: var(--g-color-text-primary); } } + + &__close-icon { + border-radius: var(--g-focus-border-radius); + + #{$block}__close:focus & { + outline: 2px solid var(--g-color-line-focus); + } + #{$block}__close:focus:not(:focus-visible) & { + outline: 0; + } + } } diff --git a/src/components/PersonaWrap/PersonaWrap.tsx b/src/components/PersonaWrap/PersonaWrap.tsx index 2ef513156d..69ae4dada8 100644 --- a/src/components/PersonaWrap/PersonaWrap.tsx +++ b/src/components/PersonaWrap/PersonaWrap.tsx @@ -36,21 +36,21 @@ export function PersonaWrap({ }: PersonaWrapProps) { const clickable = Boolean(onClick); const closeable = Boolean(onClose); + const MainComponent = clickable ? 'button' : 'div'; + return (
- {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} -
+ {avatar &&
{avatar}
}
{children}
-
+ {onClose && ( - // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -
- -
+ )}
); diff --git a/src/components/index.ts b/src/components/index.ts index e0691540f4..74083f4971 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -56,3 +56,4 @@ export {Lang, configure} from './utils/configure'; export {useOnFocusOutside} from './utils/useOnFocusOutside'; export * from './utils/interactions'; export * from './utils/xpath'; +export {getUniqId} from './utils/common';