Commit fe02900f authored by René Dudfield's avatar René Dudfield
Browse files

frontend, a11y: Improve focus handling for various components

parent 858d3a1b
Showing with 71 additions and 25 deletions
+71 -25
......@@ -91,14 +91,22 @@ export function PureAuthToken({
onChangeToken,
onCloseError,
}: PureAuthTokenProps) {
const focusedRef = React.useCallback(node => {
if (node !== null) {
node.setAttribute('tabindex', '-1');
node.focus();
}
}, []);
return (
<Box>
<ClusterDialog useCover disableEscapeKeyDown disableBackdropClick>
<DialogTitle id="responsive-dialog-title">{title}</DialogTitle>
<DialogTitle ref={focusedRef} id="responsive-dialog-title">
{title}
</DialogTitle>
<DialogContent>
<DialogContentText>Please paste your authentication token.</DialogContentText>
<TextField
autoFocus
margin="dense"
id="token"
label="ID token"
......
......@@ -219,8 +219,9 @@ export function PureAuthChooser({
onCode={handleOidcAuth}
url={oauthUrl}
title="Headlamp Cluster Authentication"
button={ColorButton as typeof Button}
>
<ColorButton>Sign In</ColorButton>
Sign In
</OauthPopup>
</Box>
) : null}
......
......@@ -5,6 +5,8 @@ exports[`Storyshots Charts/PercentageCircle No Data 1`] = `
id="root"
>
<div
aria-busy="true"
aria-live="polite"
class="MuiBox-root MuiBox-root"
>
<p
......@@ -13,7 +15,9 @@ exports[`Storyshots Charts/PercentageCircle No Data 1`] = `
CPU usage
</p>
<div
aria-label="Loading"
class="MuiBox-root MuiBox-root makeStyles-loaderContainer"
role="status"
>
<div
class="MuiCircularProgress-root MuiCircularProgress-colorPrimary MuiCircularProgress-indeterminate"
......@@ -44,6 +48,8 @@ exports[`Storyshots Charts/PercentageCircle Percent 50 1`] = `
id="root"
>
<div
aria-busy="false"
aria-live="polite"
class="MuiBox-root MuiBox-root"
>
<p
......@@ -124,6 +130,8 @@ exports[`Storyshots Charts/PercentageCircle Percent 100 1`] = `
id="root"
>
<div
aria-busy="false"
aria-live="polite"
class="MuiBox-root MuiBox-root"
>
<p
......
......@@ -101,7 +101,14 @@ export function PercentageCircle(props: PercentageCircleProps) {
}
return (
<Box justifyContent="center" alignItems="center" alignContent="center" mx="auto">
<Box
aria-busy={isLoading}
aria-live="polite"
justifyContent="center"
alignItems="center"
alignContent="center"
mx="auto"
>
{title && <Typography className={classes.title}>{title}</Typography>}
{isLoading ? (
<Loader />
......
......@@ -21,6 +21,13 @@ export function ConfirmDialog(props: ConfirmDialogProps) {
onConfirm();
}
const focusedRef = React.useCallback(node => {
if (node !== null) {
node.setAttribute('tabindex', '-1');
node.focus();
}
}, []);
return (
<div>
<Dialog
......@@ -29,12 +36,14 @@ export function ConfirmDialog(props: ConfirmDialogProps) {
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{title}</DialogTitle>
<DialogTitle ref={focusedRef} id="alert-dialog-title">
{title}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">{description}</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary" autoFocus>
<Button onClick={handleClose} color="primary">
No
</Button>
<Button onClick={onConfirmationClicked} color="primary">
......
......@@ -13,19 +13,6 @@ exports[`Storyshots Label/StatusLabel Error 1`] = `
</div>
`;
exports[`Storyshots Label/StatusLabel Status Label 1`] = `
<div
id="root"
>
<span
class="MuiTypography-root makeStyles-statusLabel MuiTypography-body1"
style="background-color: rgb(232, 245, 233); color: rgb(76, 175, 80);"
>
status
</span>
</div>
`;
exports[`Storyshots Label/StatusLabel Success 1`] = `
<div
id="root"
......
......@@ -21,7 +21,7 @@ export default function Loader(props: LoaderProps & CircularProgressProps) {
if (noContainer) return progress;
return (
<Box className={classes.loaderContainer} py={3} px="auto">
<Box className={classes.loaderContainer} py={3} px="auto" aria-label="Loading" role="status">
{progress}
</Box>
);
......
......@@ -206,13 +206,27 @@ export default function EditorDialog(props: EditorDialogProps) {
: `Edit: ${item.metadata?.name || 'New Object'}`;
}
const focusedRef = React.useCallback(node => {
if (node !== null) {
node.setAttribute('tabindex', '-1');
node.focus();
}
}, []);
return (
<Dialog maxWidth="lg" scroll="paper" fullWidth onBackdropClick={onClose} {...other}>
<Dialog
aria-busy={!item}
maxWidth="lg"
scroll="paper"
fullWidth
onBackdropClick={onClose}
{...other}
>
{!item ? (
<Loader />
) : (
<React.Fragment>
<DialogTitle>{dialogTitle}</DialogTitle>
<DialogTitle ref={focusedRef}>{dialogTitle}</DialogTitle>
<DialogContent className={classes.dialogContent}>
{isReadOnly() ? (
<OurEditor />
......@@ -255,7 +269,7 @@ export default function EditorDialog(props: EditorDialogProps) {
<div style={{ flex: '1 0 0' }} />
{errorLabel && <Typography color="error">{errorLabel}</Typography>}
<div style={{ flex: '1 0 0' }} />
<Button onClick={onClose} color="primary" autoFocus>
<Button onClick={onClose} color="primary">
Close
</Button>
{!isReadOnly() && (
......
......@@ -106,6 +106,8 @@ export function MainInfoSection(props: MainInfoSectionProps) {
</Button>
)}
<SectionBox
aria-busy={resource === null}
aria-live="polite"
title={
<SectionHeader
title={title || (resource ? resource.kind : '')}
......
......@@ -44,6 +44,12 @@ export default function SectionFilterHeader(props: SectionFilterHeaderProps) {
}
});
const focusedRef = React.useCallback(node => {
if (node !== null) {
node.focus();
}
}, []);
React.useEffect(
() => {
const namespace = getFilterValueByNameFromURL('namespace', location);
......@@ -95,8 +101,8 @@ export default function SectionFilterHeader(props: SectionFilterHeaderProps) {
InputLabelProps={{ shrink: true }}
placeholder="Filter"
value={filter.search}
autoFocus
onChange={event => dispatch(setSearchFilter(event.target.value))}
ref={focusedRef}
/>
</Grid>
<Grid item>
......
......@@ -5,7 +5,9 @@ exports[`Storyshots Loader With Container 1`] = `
id="root"
>
<div
aria-label="Loading"
class="MuiBox-root MuiBox-root makeStyles-loaderContainer"
role="status"
>
<div
class="MuiCircularProgress-root MuiCircularProgress-colorPrimary MuiCircularProgress-indeterminate"
......
import Button from '@material-ui/core/Button';
import React, { ReactChild } from 'react';
interface OauthPopupProps {
......@@ -8,6 +9,7 @@ interface OauthPopupProps {
onClose?: () => any;
onCode: (params: any) => any;
children?: ReactChild;
button: typeof Button;
}
const defaultOauthPopupProps = {
......@@ -78,7 +80,7 @@ const OauthPopup: React.FC<OauthPopupProps> = props => {
}
};
return <div onClick={createPopup}>{props.children}</div>;
return <props.button onClick={createPopup}>{props.children}</props.button>;
};
export default OauthPopup;
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment