-
Notifications
You must be signed in to change notification settings - Fork 843
Expand file tree
/
Copy pathModal.tsx
More file actions
143 lines (129 loc) · 3.88 KB
/
Modal.tsx
File metadata and controls
143 lines (129 loc) · 3.88 KB
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import React, { useEffect } from "react";
import classnames from "classnames";
import Button from "components/buttons/Button/Button";
import Icon from "components/Icon/Icon";
const baseClass = "modal";
type ModalWidth = "medium" | "large" | "xlarge" | "auto";
// 650px 800px 850px auto
export interface IModalProps {
title: string | JSX.Element;
children: React.ReactNode;
onExit: () => void;
onEnter?: () => void;
/** medium 650px, large 800px, xlarge 850px, auto auto-width
* @default "medium"
*/
width?: ModalWidth;
/** isHidden can be set true to hide the modal when opening another modal
* @default false
*/
isHidden?: boolean;
/** isLoading can be set true to enable targeting elements by loading state
* @default false
*/
isLoading?: boolean;
/** `isContentDisabled` can be set to true to display the modal content as disabled.
* At the moment this will place an overlay over the modal content and make it
* unclickable. The top right will not be disabled and will still be clickable.
*
* @default false
*/
isContentDisabled?: boolean;
/** `disableClosingModal` can be set to disable the users ability to manually
* close the modal.
* @default false
* */
disableClosingModal?: boolean;
className?: string;
}
const Modal = ({
title,
children,
onExit,
onEnter,
width = "medium",
isHidden = false,
isLoading = false,
isContentDisabled = false,
disableClosingModal = false,
className,
}: IModalProps): JSX.Element => {
useEffect(() => {
const closeWithEscapeKey = (e: KeyboardEvent) => {
if (e.key === "Escape") {
onExit();
}
};
if (!disableClosingModal) {
document.addEventListener("keydown", closeWithEscapeKey);
}
return () => {
if (!disableClosingModal) {
document.removeEventListener("keydown", closeWithEscapeKey);
}
};
}, [disableClosingModal, onExit]);
useEffect(() => {
if (onEnter) {
const closeOrSaveWithEnterKey = (event: KeyboardEvent) => {
if (event.code === "Enter" || event.code === "NumpadEnter") {
event.preventDefault();
onEnter();
}
};
document.addEventListener("keydown", closeOrSaveWithEnterKey);
return () => {
document.removeEventListener("keydown", closeOrSaveWithEnterKey);
};
}
return undefined;
}, [onEnter]);
const backgroundClasses = classnames(`${baseClass}__background`, {
[`${baseClass}__hidden`]: isHidden,
});
const modalContainerClasses = classnames(
className,
`${baseClass}__modal_container`,
`${baseClass}__modal_container__${width}`,
{
[`${className}__loading`]: isLoading,
}
);
const contentWrapperClasses = classnames(`${baseClass}__content-wrapper`, {
[`${baseClass}__content-wrapper-disabled`]: isContentDisabled,
});
const contentClasses = classnames(`${baseClass}__content`, {
[`${baseClass}__content-disabled`]: isContentDisabled,
});
return (
<div className={backgroundClasses}>
<div
className={modalContainerClasses}
tabIndex={-1} // Make focusable
>
<div className={`${baseClass}__header`}>
<span>{title}</span>
{!disableClosingModal && (
<div className={`${baseClass}__ex`}>
<Button
variant="icon"
onClick={onExit}
iconStroke
autofocus={isContentDisabled}
>
<Icon name="close" color="core-fleet-black" size="medium" />
</Button>
</div>
)}
</div>
<div className={contentWrapperClasses}>
{isContentDisabled && (
<div className={`${baseClass}__disabled-overlay`} />
)}
<div className={contentClasses}>{children}</div>
</div>
</div>
</div>
);
};
export default Modal;