Focus trap and Modal Functionality (#145)

* Focus trap and Modal Functionality

* Changes

* Changes

* Update components/ui/Modal/Modal.tsx

Co-authored-by: Luis Alvarez D. <luis@vercel.com>

* changes

Co-authored-by: Luis Alvarez D. <luis@vercel.com>
This commit is contained in:
B
2021-01-09 11:03:03 -03:00
committed by GitHub
parent 86c396edd5
commit 66b8bdb6bb
8 changed files with 538 additions and 735 deletions

View File

@@ -4,7 +4,7 @@
}
.modal {
@apply bg-primary p-12 border border-accents-2;
@apply bg-primary p-12 border border-accents-2 relative;
}
.modal:focus {

View File

@@ -1,4 +1,4 @@
import { FC, useRef, useEffect } from 'react'
import { FC, useRef, useEffect, useCallback } from 'react'
import Portal from '@reach/portal'
import s from './Modal.module.css'
import { Cross } from '@components/icons'
@@ -7,45 +7,53 @@ import {
enableBodyScroll,
clearAllBodyScrollLocks,
} from 'body-scroll-lock'
import FocusTrap from '@lib/focus-trap'
interface Props {
className?: string
children?: any
open?: boolean
onClose: () => void
onEnter?: () => void | null
}
const Modal: FC<Props> = ({ children, open, onClose }) => {
const Modal: FC<Props> = ({ children, open, onClose, onEnter = null }) => {
const ref = useRef() as React.MutableRefObject<HTMLDivElement>
const handleKey = (e: KeyboardEvent) =>
useCallback(() => {
if (e.key === 'Escape') {
return onClose()
}
}, [onClose])
useEffect(() => {
if (ref.current) {
if (open) {
disableBodyScroll(ref.current)
window.addEventListener('keydown', handleKey)
} else {
enableBodyScroll(ref.current)
}
}
return () => {
window.removeEventListener('keydown', handleKey)
clearAllBodyScrollLocks()
}
}, [open])
}, [open, handleKey])
return (
<Portal>
{open ? (
<div className={s.root} ref={ref}>
<div className={s.modal}>
<div className="h-7 flex items-center justify-end w-full">
<button
onClick={() => onClose()}
aria-label="Close panel"
className="hover:text-gray-500 transition ease-in-out duration-150 focus:outline-none"
>
<Cross className="h-6 w-6" />
</button>
</div>
{children}
<div className={s.root}>
<div className={s.modal} role="dialog" ref={ref}>
<button
onClick={() => onClose()}
aria-label="Close panel"
className="hover:text-gray-500 transition ease-in-out duration-150 focus:outline-none absolute right-0 top-0 m-6"
>
<Cross className="h-6 w-6" />
</button>
<FocusTrap focusFirst>{children}</FocusTrap>
</div>
</div>
) : null}