A11y : Fix option panes not accessible when collapsed (#46405)

* Turned div into text button to make it accessible

* Only icon as button to avoid embedded buttons with overrides delete button

* use icon in Button directly

* Removed unused import

* moving id for labelledBy to h6 elem instead of icon

* Tweaking style, bigger caret

* Fixed aria-expanded

* Modifying and using CollapseToggle from unified alerting

* Added restOfProps to CollapseToggle
This commit is contained in:
Yaelle Chaudy 2022-03-14 15:37:13 +01:00 committed by GitHub
parent 2409405c34
commit 0b0d612372
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 32 deletions

View File

@ -1,43 +1,45 @@
import React, { FC, HTMLAttributes } from 'react';
import { css, cx } from '@emotion/css';
import { IconSize, useStyles, Icon } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import { IconSize, useStyles2, Button } from '@grafana/ui';
interface Props extends HTMLAttributes<HTMLButtonElement> {
isCollapsed: boolean;
onToggle: (isCollapsed: boolean) => void;
// Todo: this should be made compulsory for a11y purposes
idControlled?: string;
size?: IconSize;
className?: string;
text?: string;
}
export const CollapseToggle: FC<Props> = ({ isCollapsed, onToggle, className, text, size = 'xl', ...restOfProps }) => {
const styles = useStyles(getStyles);
export const CollapseToggle: FC<Props> = ({
isCollapsed,
onToggle,
idControlled,
className,
text,
size = 'xl',
...restOfProps
}) => {
const styles = useStyles2(getStyles);
return (
<button
aria-label={`${isCollapsed ? 'Expand' : 'Collapse'} alert group`}
<Button
fill="text"
aria-expanded={!isCollapsed}
aria-controls={idControlled}
className={cx(styles.expandButton, className)}
icon={isCollapsed ? 'angle-right' : 'angle-down'}
onClick={() => onToggle(!isCollapsed)}
{...restOfProps}
>
<Icon size={size} name={isCollapsed ? 'angle-right' : 'angle-down'} />
{text}
</button>
/>
);
};
export const getStyles = () => ({
export const getStyles = (theme: GrafanaTheme2) => ({
expandButton: css`
background: none;
border: none;
outline: none !important;
display: inline-flex;
align-items: center;
svg {
margin-bottom: 0;
}
color: ${theme.colors.text.secondary};
margin-right: ${theme.spacing(1)};
`,
});

View File

@ -1,11 +1,12 @@
import React, { FC, ReactNode, useCallback, useEffect, useState, useRef } from 'react';
import { css, cx } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { Counter, Icon, useStyles2 } from '@grafana/ui';
import { Counter, useStyles2 } from '@grafana/ui';
import { PANEL_EDITOR_UI_STATE_STORAGE_KEY } from './state/reducers';
import { useLocalStorage } from 'react-use';
import { selectors } from '@grafana/e2e-selectors';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { CollapseToggle } from 'app/features/alerting/unified/components/CollapseToggle';
export interface OptionsPaneCategoryProps {
id: string;
@ -101,12 +102,16 @@ export const OptionsPaneCategory: FC<OptionsPaneCategoryProps> = React.memo(
ref={ref}
>
<div className={headerStyles} onClick={onToggle} aria-label={selectors.components.OptionsGroup.toggle(id)}>
<div className={cx(styles.toggle, 'editor-options-group-toggle')}>
<Icon name={isExpanded ? 'angle-down' : 'angle-right'} />
</div>
<h6 className={styles.title}>{renderTitle(isExpanded)}</h6>
<CollapseToggle isCollapsed={!isExpanded} idControlled={id} onToggle={onToggle} />
<h6 id={`button-${id}`} className={styles.title}>
{renderTitle(isExpanded)}
</h6>
</div>
{isExpanded && <div className={bodyStyles}>{children}</div>}
{isExpanded && (
<div className={bodyStyles} id={id} aria-labelledby={`button-${id}`}>
{children}
</div>
)}
</div>
);
}
@ -122,10 +127,6 @@ const getStyles = (theme: GrafanaTheme2) => {
boxNestedExpanded: css`
margin-bottom: ${theme.spacing(2)};
`,
toggle: css`
color: ${theme.colors.text.secondary};
margin-right: ${theme.spacing(1)};
`,
title: css`
flex-grow: 1;
overflow: hidden;
@ -138,7 +139,7 @@ const getStyles = (theme: GrafanaTheme2) => {
display: flex;
cursor: pointer;
align-items: baseline;
padding: ${theme.spacing(1)};
padding: ${theme.spacing(0.5)};
color: ${theme.colors.text.primary};
font-weight: ${theme.typography.fontWeightMedium};