Skip to content

Commit

Permalink
Hotfix/replace modal focus with npm solution (#264)
Browse files Browse the repository at this point in the history
* added FocusTrap to Modal and removed messy code

* 3.1.31
  • Loading branch information
KitoC authored Mar 27, 2024
1 parent f16358f commit bc6625c
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 122 deletions.
192 changes: 73 additions & 119 deletions lib/components/Modal/index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState
} from "react";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import ReactDOM from "react-dom";
import useOnclickOutside from "react-cool-onclickoutside";
import PropTypes from "prop-types";
import styled, { keyframes, ThemeProvider } from "styled-components";
import FocusTrap from "focus-trap-react";

import { css } from "@styled-system/css";
import { themeGet } from "@styled-system/theme-get";

import { commonKeys } from "../../hooks/keypress";

import Icon from "../Icon";
import Button from "../Button";
import Flex from "../Flex";
Expand Down Expand Up @@ -151,21 +144,6 @@ const ScrollableContent = styled.div`

const isHidden = (el) => window.getComputedStyle(el).display === "none";

const makeRootNotFocusable = () => {
const root = document.getElementById("root");

root?.setAttribute("aria-hidden", true);
root?.setAttribute("inert", true);
};

// Make root focusable again
const makeRootFocusable = () => {
const root = document.getElementById("root");

root?.removeAttribute("aria-hidden");
root?.removeAttribute("inert");
};

const Modal = ({
children,
width,
Expand Down Expand Up @@ -202,27 +180,6 @@ const Modal = ({
}
}, [restProps.ariaLabel, headerContent]);

// Initial focus point for keyboard navigation
const modalContainerRef = useRef();

// If bottom becomes focused then re-focus the close button

// Ref to close button
const button = useRef();

const setFocus = useCallback(() => {
const autoFocusable = modalContainerRef.current.querySelector(
"*[autofocus='true']"
);
const firstInput = modalContainerRef.current.querySelectorAll("input")[0];

if (autoFocusable) {
autoFocusable.focus();
} else {
firstInput?.focus();
}
}, [modalContainerRef]);

const focusLastActiveElement = useCallback(() => {
if (!lastActiveElement) return;

Expand All @@ -242,93 +199,90 @@ const Modal = ({

// On becoming visible focus the top
useEffect(() => {
if (visible) {
if (!lastActiveElement) {
// Keep track of last clicked element to refocus to after dialog closes
setLastActiveElement(document.activeElement);
}

// Prevents tabbing of elements underneath modal overlay
makeRootNotFocusable();

// See function
setFocus();
} else if (!visible) {
makeRootFocusable();
if (visible && !lastActiveElement) {
// Keep track of last clicked element to refocus to after dialog closes
setLastActiveElement(document.activeElement);
} else {
setLastActiveElement(null);

// Focus the last active element before modal open when modal is closed
focusLastActiveElement();
}
}, [visible, setFocus, focusLastActiveElement, lastActiveElement]);
}, [visible, focusLastActiveElement, lastActiveElement]);

const component = (
<Overlay
alignItems="center"
justifyContent="center"
onKeyUp={(e) => {
e.stopPropagation();

if ([commonKeys.ESCAPE, commonKeys.ESC].includes(e.key)) {
onClose();
}
}}
id={overlayID}
{...restProps}
>
<div
ref={modalRef}
role="dialog"
aria-modal="true"
aria-label={ariaLabel}
>
<Container
width={width}
height={height}
maxWidth={maxWidth}
maxHeight={maxHeight}
minWidth={minWidth}
minHeight={minHeight}
overflow={overflow}
borderRadius="2"
bg="white"
p="r"
id={modalID}
ref={modalContainerRef}
>
{headerContent ? (
<HeaderContent>
<Box mr="xl" width="100%">
{headerContent}
</Box>
<CloseButton
ref={button}
onClick={onClose}
className="modal-close"
small
px="6px"
aria-label="Close dialog"
>
<Icon icon={["fas", "times"]} color="greyDark" size="lg" />
</CloseButton>
</HeaderContent>
) : (
<CloseButton
ref={button}
onClick={onClose}
className="modal-close"
small
px="6px"
aria-label="Close dialog"
{visible && (
<FocusTrap focusTrapOptions={{ onDeactivate: onClose }}>
<div>
<div
ref={modalRef}
role="dialog"
aria-modal="true"
aria-label={ariaLabel}
>
<Icon icon={["fas", "times"]} color="greyDark" size="lg" />
</CloseButton>
)}
<ScrollableContent headerContent={headerContent} overflow={overflow}>
{children}
</ScrollableContent>
{footerContent && <FooterContent>{footerContent}</FooterContent>}
</Container>
</div>
<Container
width={width}
height={height}
maxWidth={maxWidth}
maxHeight={maxHeight}
minWidth={minWidth}
minHeight={minHeight}
overflow={overflow}
borderRadius="2"
bg="white"
p="r"
id={modalID}
>
{headerContent ? (
<HeaderContent>
<Box mr="xl" width="100%">
{headerContent}
</Box>
<CloseButton
onClick={onClose}
className="modal-close"
small
px="6px"
aria-label="Close dialog"
>
<Icon
icon={["fas", "times"]}
color="greyDark"
size="lg"
/>
</CloseButton>
</HeaderContent>
) : (
<CloseButton
onClick={onClose}
className="modal-close"
small
px="6px"
aria-label="Close dialog"
>
<Icon icon={["fas", "times"]} color="greyDark" size="lg" />
</CloseButton>
)}
<ScrollableContent
headerContent={headerContent}
overflow={overflow}
>
{children}
</ScrollableContent>
{footerContent && (
<FooterContent>{footerContent}</FooterContent>
)}
</Container>
</div>
</div>
</FocusTrap>
)}
</Overlay>
);

Expand Down
32 changes: 30 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "orcs-design-system",
"version": "3.1.30",
"version": "3.1.31",
"engines": {
"node": "18.17.1"
},
Expand Down Expand Up @@ -47,6 +47,7 @@
"@styled-system/prop-types": "^5.1.5",
"@styled-system/should-forward-prop": "^5.1.5",
"@styled-system/theme-get": "^5.1.2",
"focus-trap-react": "^10.2.3",
"moment": "^2.29.4",
"polished": "^3.7.1",
"prop-types": "^15.6.2",
Expand Down

0 comments on commit bc6625c

Please sign in to comment.