fix(dialog) Wrap dialog in FocusLock (#12431)

Improve accessibility by not allowing the user to navigate outside the dialog
This commit is contained in:
Robert Pintilii 2022-10-21 10:42:00 +03:00 committed by GitHub
parent 0b48e55a35
commit 4755f5a031
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 47 additions and 41 deletions

View File

@ -1,5 +1,6 @@
import { Theme } from '@mui/material'; import { Theme } from '@mui/material';
import React, { useCallback, useContext, useEffect } from 'react'; import React, { useCallback, useContext, useEffect } from 'react';
import FocusLock from 'react-focus-lock';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { keyframes } from 'tss-react'; import { keyframes } from 'tss-react';
@ -57,7 +58,6 @@ const useStyles = makeStyles()((theme: Theme) => {
}, },
modal: { modal: {
zIndex: 1,
backgroundColor: theme.palette.ui01, backgroundColor: theme.palette.ui01,
border: `1px solid ${theme.palette.ui03}`, border: `1px solid ${theme.palette.ui03}`,
boxShadow: '0px 4px 25px 4px rgba(20, 20, 20, 0.6)', boxShadow: '0px 4px 25px 4px rgba(20, 20, 20, 0.6)',
@ -168,6 +168,10 @@ const useStyles = makeStyles()((theme: Theme) => {
'& button:last-child': { '& button:last-child': {
marginLeft: '16px' marginLeft: '16px'
} }
},
focusLock: {
zIndex: 1
} }
}; };
}); });
@ -255,47 +259,49 @@ const Dialog = ({
<div <div
className = { classes.backdrop } className = { classes.backdrop }
onClick = { onBackdropClick } /> onClick = { onBackdropClick } />
<div <FocusLock className = { classes.focusLock }>
aria-describedby = { description } <div
aria-labelledby = { title ?? t(titleKey ?? '') } aria-describedby = { description }
aria-modal = { true } aria-labelledby = { title ?? t(titleKey ?? '') }
className = { cx(classes.modal, isUnmounting && 'unmount', size, className) } aria-modal = { true }
role = 'dialog'> className = { cx(classes.modal, isUnmounting && 'unmount', size, className) }
<div className = { classes.header }> role = 'dialog'>
<p <div className = { classes.header }>
className = { classes.title } <p
id = 'dialog-title'> className = { classes.title }
{title ?? t(titleKey ?? '')} id = 'dialog-title'>
</p> {title ?? t(titleKey ?? '')}
{!hideCloseButton && ( </p>
<ClickableIcon {!hideCloseButton && (
accessibilityLabel = { t('dialog.close') } <ClickableIcon
icon = { IconClose } accessibilityLabel = { t('dialog.close') }
id = 'modal-header-close-button' icon = { IconClose }
onClick = { onClose } /> id = 'modal-header-close-button'
)} onClick = { onClose } />
)}
</div>
<div className = { classes.content }>{children}</div>
<div className = { classes.footer }>
{!back.hidden && <Button
accessibilityLabel = { t(back.translationKey ?? '') }
labelKey = { back.translationKey }
// eslint-disable-next-line react/jsx-handler-names
onClick = { back.onClick }
type = 'secondary' />}
{!cancel.hidden && <Button
accessibilityLabel = { t(cancel.translationKey ?? '') }
labelKey = { cancel.translationKey }
onClick = { onClose }
type = 'tertiary' />}
{!ok.hidden && <Button
accessibilityLabel = { t(ok.translationKey ?? '') }
disabled = { ok.disabled }
id = 'modal-dialog-ok-button'
labelKey = { ok.translationKey }
onClick = { submit } />}
</div>
</div> </div>
<div className = { classes.content }>{children}</div> </FocusLock>
<div className = { classes.footer }>
{!back.hidden && <Button
accessibilityLabel = { t(back.translationKey ?? '') }
labelKey = { back.translationKey }
// eslint-disable-next-line react/jsx-handler-names
onClick = { back.onClick }
type = 'secondary' />}
{!cancel.hidden && <Button
accessibilityLabel = { t(cancel.translationKey ?? '') }
labelKey = { cancel.translationKey }
onClick = { onClose }
type = 'tertiary' />}
{!ok.hidden && <Button
accessibilityLabel = { t(ok.translationKey ?? '') }
disabled = { ok.disabled }
id = 'modal-dialog-ok-button'
labelKey = { ok.translationKey }
onClick = { submit } />}
</div>
</div>
</div> </div>
); );
}; };