summaryrefslogtreecommitdiffhomepage
path: root/gui/src
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2020-09-21 23:21:55 +0200
committerOskar Nyberg <oskar@mullvad.net>2020-09-29 11:45:50 +0200
commitc98cbddd3f2fc704a6096b9edce6d802c056074e (patch)
tree10ae0355fa4d336cce3c7fe79ffdbbf036301991 /gui/src
parentff1d73b504bf425c6deb0563990ca7f2e9afb4b1 (diff)
downloadmullvadvpn-c98cbddd3f2fc704a6096b9edce6d802c056074e.tar.xz
mullvadvpn-c98cbddd3f2fc704a6096b9edce6d802c056074e.zip
Restore focus when closing modal
Diffstat (limited to 'gui/src')
-rw-r--r--gui/src/renderer/components/Modal.tsx37
1 files changed, 34 insertions, 3 deletions
diff --git a/gui/src/renderer/components/Modal.tsx b/gui/src/renderer/components/Modal.tsx
index b045803626..b1303ad45f 100644
--- a/gui/src/renderer/components/Modal.tsx
+++ b/gui/src/renderer/components/Modal.tsx
@@ -1,4 +1,4 @@
-import React, { useContext, useRef, useState } from 'react';
+import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';
import { colors } from '../../config.json';
@@ -41,6 +41,7 @@ interface IModalContext {
activeModal: boolean;
setActiveModal: (value: boolean) => void;
modalContainerRef: React.RefObject<HTMLDivElement>;
+ previousActiveElement: React.MutableRefObject<HTMLElement | undefined>;
}
const noActiveModalContextError = new Error('ActiveModalContext.Provider missing');
@@ -54,14 +55,34 @@ const ActiveModalContext = React.createContext<IModalContext>({
get modalContainerRef(): React.RefObject<HTMLDivElement> {
throw noActiveModalContextError;
},
+ get previousActiveElement(): React.MutableRefObject<HTMLElement | undefined> {
+ throw noActiveModalContextError;
+ },
});
export function ModalContainer(props: IModalContainerProps) {
const [activeModal, setActiveModal] = useState(false);
+ const previousActiveElement = useRef<HTMLElement>();
const modalContainerRef = useRef() as React.RefObject<HTMLDivElement>;
+ const contextValue = useMemo(
+ () => ({
+ activeModal,
+ setActiveModal,
+ modalContainerRef,
+ previousActiveElement,
+ }),
+ [activeModal],
+ );
+
+ useEffect(() => {
+ if (!activeModal) {
+ previousActiveElement.current?.focus();
+ }
+ }, [activeModal]);
+
return (
- <ActiveModalContext.Provider value={{ activeModal, setActiveModal, modalContainerRef }}>
+ <ActiveModalContext.Provider value={contextValue}>
<StyledModalContainer ref={modalContainerRef}>
<ModalContent aria-hidden={activeModal}>{props.children}</ModalContent>
</StyledModalContainer>
@@ -118,8 +139,17 @@ export function ModalAlert(props: IModalAlertProps) {
class ModalAlertWithContext extends React.Component<IModalAlertProps & IModalContext> {
private element = document.createElement('div');
+ private modalRef = React.createRef<HTMLDivElement>();
private appendScheduler = new Scheduler();
+ constructor(props: IModalAlertProps & IModalContext) {
+ super(props);
+
+ if (document.activeElement) {
+ props.previousActiveElement.current = document.activeElement as HTMLElement;
+ }
+ }
+
public componentDidMount() {
this.props.setActiveModal(true);
document.addEventListener('keydown', this.handleKeyPress);
@@ -131,6 +161,7 @@ class ModalAlertWithContext extends React.Component<IModalAlertProps & IModalCon
// Postponing it to the next event cycle solves this issue.
this.appendScheduler.schedule(() => {
modalContainer.appendChild(this.element);
+ this.modalRef.current?.focus();
});
} else {
throw Error('Modal container not found when mounting modal');
@@ -153,7 +184,7 @@ class ModalAlertWithContext extends React.Component<IModalAlertProps & IModalCon
return (
<ModalBackground>
<ModalAlertContainer>
- <StyledModalAlert role="alertdialog">
+ <StyledModalAlert ref={this.modalRef} tabIndex={-1} role="dialog" aria-modal>
{this.props.type && (
<ModalAlertIcon>{this.renderTypeIcon(this.props.type)}</ModalAlertIcon>
)}