-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
Copy pathindex.jsx
101 lines (86 loc) · 2.58 KB
/
index.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import React, { Fragment, useState, useRef, useEffect, useCallback } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
import useOnEscapeKeyDown from 'shared/hooks/onEscapeKeyDown';
import { ScrollOverlay, ClickableOverlay, StyledModal, CloseIcon } from './Styles';
const propTypes = {
className: PropTypes.string,
testid: PropTypes.string,
variant: PropTypes.oneOf(['center', 'aside']),
width: PropTypes.number,
withCloseIcon: PropTypes.bool,
isOpen: PropTypes.bool,
onClose: PropTypes.func,
renderLink: PropTypes.func,
renderContent: PropTypes.func.isRequired,
};
const defaultProps = {
className: undefined,
testid: 'modal',
variant: 'center',
width: 600,
withCloseIcon: true,
isOpen: undefined,
onClose: () => {},
renderLink: () => {},
};
const Modal = ({
className,
testid,
variant,
width,
withCloseIcon,
isOpen: propsIsOpen,
onClose: tellParentToClose,
renderLink,
renderContent,
}) => {
const [stateIsOpen, setStateOpen] = useState(false);
const isControlled = typeof propsIsOpen === 'boolean';
const isOpen = isControlled ? propsIsOpen : stateIsOpen;
const $modalRef = useRef();
const $clickableOverlayRef = useRef();
const closeModal = useCallback(() => {
if (!isControlled) {
setStateOpen(false);
} else {
tellParentToClose();
}
}, [isControlled, tellParentToClose]);
useOnOutsideClick($modalRef, isOpen, closeModal, $clickableOverlayRef);
useOnEscapeKeyDown(isOpen, closeModal);
useEffect(() => {
document.body.style.overflow = 'hidden';
return () => {
document.body.style.overflow = 'visible';
};
}, [isOpen]);
return (
<Fragment>
{!isControlled && renderLink({ open: () => setStateOpen(true) })}
{isOpen &&
ReactDOM.createPortal(
<ScrollOverlay>
<ClickableOverlay variant={variant} ref={$clickableOverlayRef}>
<StyledModal
className={className}
variant={variant}
width={width}
data-testid={testid}
ref={$modalRef}
>
{withCloseIcon && <CloseIcon type="close" variant={variant} onClick={closeModal} />}
{renderContent({ close: closeModal })}
</StyledModal>
</ClickableOverlay>
</ScrollOverlay>,
$root,
)}
</Fragment>
);
};
const $root = document.getElementById('root');
Modal.propTypes = propTypes;
Modal.defaultProps = defaultProps;
export default Modal;