Last active
September 25, 2023 20:38
-
-
Save ChrisCrossCrash/f53b4f303d4361c210d8c1d61ce03492 to your computer and use it in GitHub Desktop.
A React TypeScript component that uses the `HTMLDialogElement`.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useRef, useEffect } from 'react' | |
type ModalProps = { | |
className?: string | |
children: React.ReactNode | |
/** Whether the modal is currently open or not. */ | |
isOpen: boolean | |
/** Function to set the modal's visibility state. */ | |
setIsOpen: (isOpen: boolean) => void | |
/** If true, allows closing the modal by clicking outside of it. Defaults to `false`. */ | |
allowClickOut?: boolean | |
} | |
/** | |
* Modal component using the | |
* [HTMLDialogElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement). | |
* | |
* This component displays its children content inside a modal dialog. | |
* The modal's visibility is controlled via the `isOpen` prop. | |
* | |
* @returns The rendered Modal component. | |
*/ | |
function Modal(props: ModalProps) { | |
const modalRef = useRef<HTMLDialogElement>(null) | |
useEffect(() => { | |
const modal = modalRef.current | |
if (modal) { | |
if (props.isOpen) { | |
modal.showModal() | |
} else { | |
modal.close() | |
} | |
} | |
}, [props.isOpen]) | |
const handleClose = () => { | |
props.setIsOpen(false) | |
} | |
const handleClick = (e: React.MouseEvent<HTMLDialogElement>) => { | |
// Close the modal if the user clicks outside of it and `allowClickOut` is `true`. | |
if (!props.allowClickOut) return | |
const modal = modalRef.current | |
if (!modal) return | |
if ( | |
e.clientX < e.currentTarget.offsetLeft || | |
e.clientX > e.currentTarget.offsetLeft + e.currentTarget.offsetWidth || | |
e.clientY < e.currentTarget.offsetTop || | |
e.clientY > e.currentTarget.offsetTop + e.currentTarget.offsetHeight | |
) { | |
modal.close() | |
} | |
} | |
return ( | |
<dialog | |
className={props.className} | |
ref={modalRef} | |
onClose={handleClose} | |
onClick={handleClick} | |
> | |
{props.children} | |
</dialog> | |
) | |
} | |
export default Modal |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment