import React, { ReactNode, useRef, useEffect } from 'react'; import { Overlay, useModalOverlay, useDialog, useKeyboard } from 'react-aria'; import { OverlayTriggerState } from 'react-stately'; import { DOMAttributes, FocusableElement } from '@react-types/shared'; import { Icon, IconOptions } from '../Icons/Icon'; /* This has to be a separate element otherwise the focus trap fails. Assuming this is because it needs to fit inside the 'Overlay' as a form of context. */ function PreviewModalContent({ children, onClose, ...props }: { children: ReactNode; onClose: () => void }) { const ref = useRef(null); const { dialogProps, titleProps } = useDialog(props, ref); return (

Resource Details

{children}
); } export type PreviewModalProps = { state: OverlayTriggerState; overlayProps: DOMAttributes; children?: ReactNode; onClose: () => void; }; // Accept a ref for the top level modal function PreviewModal({ state, overlayProps, children, onClose, ...props }: PreviewModalProps) { const modalRef = useRef(null); const overlayRef = useRef(null); const { modalProps, underlayProps } = useModalOverlay( { isKeyboardDismissDisabled: true, ...props }, state, overlayRef, ); // Need to handle the ESC escape hatch ourselves as we need to run onClose to deselect the current node const { keyboardProps } = useKeyboard({ onKeyDown: (e) => { if (e.key === 'Escape') { onClose(); } else { // Need to do this so TAB get handled up higher and cycles though the focus trap e.continuePropagation(); } }, }); useEffect(() => { // Check if the click event has happened outside the modal function handleClickOutside(event: MouseEvent) { if (modalRef.current && !modalRef.current.contains(event?.target as Node)) { onClose(); } } // Bind the event listener document.addEventListener('mousedown', handleClickOutside); return () => { // Unbind the event listener on clean up document.removeEventListener('mousedown', handleClickOutside); }; }, [modalRef]); return (
{children}
); } export default PreviewModal;