fix(dialog) Wrap dialog in FocusLock (#12431)
Improve accessibility by not allowing the user to navigate outside the dialog
This commit is contained in:
parent
0b48e55a35
commit
4755f5a031
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue