forked from zyf722/livecodes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
modal.ts
122 lines (110 loc) · 3.44 KB
/
modal.ts
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
// eslint-disable-next-line import/no-internal-modules
import { translate } from './i18n/utils';
interface ModalOptions {
size?: 'large' | 'small';
closeButton?: boolean;
isAsync?: boolean;
onClose?: () => void;
scrollToSelector?: string;
}
export const createModal = ({
i18n,
}: { i18n?: typeof import('./i18n/i18n').default | undefined } = {}) => {
const overlay = document.querySelector('#overlay') as HTMLElement;
const modalContainer = document.querySelector('#modal-container') as HTMLElement;
const modal = document.querySelector('#modal') as HTMLElement;
let isOpening: boolean;
let onCloseFn: () => void = () => undefined;
const show = (
container: HTMLElement,
{
size = 'large',
closeButton = false,
isAsync = false,
onClose = () => undefined,
scrollToSelector = '',
}: ModalOptions = {},
) => {
modal.innerHTML = '';
modal.className = size;
translate(container, i18n);
modal.appendChild(container);
onCloseFn = onClose;
if (scrollToSelector) {
setTimeout(() => {
const target = container.querySelector<HTMLElement>(scrollToSelector);
container.style.scrollBehavior = 'smooth';
if (target) {
target.scrollIntoView();
}
}, 500);
}
if (closeButton) {
const closeContainer = document.createElement('div');
closeContainer.className = 'close-container';
const closeBtn = document.createElement('button');
closeBtn.classList.add('button');
closeBtn.innerHTML = 'Close';
closeBtn.onclick = close;
closeContainer.appendChild(closeBtn);
modal.appendChild(closeContainer);
}
const cornerCloseBtn = document.createElement('div');
cornerCloseBtn.classList.add('close-button');
cornerCloseBtn.title = 'Esc';
cornerCloseBtn.onclick = close;
modal.appendChild(cornerCloseBtn);
overlay.style.display = 'flex';
modalContainer.style.display = 'flex';
modal.style.display = 'flex';
overlay.classList.remove('hidden');
modalContainer.classList.remove('hidden');
isOpening = true;
// remove previous event listener if it was not cleared
document.removeEventListener('click', onClickOutside);
document.removeEventListener('keydown', escapeListener);
document.addEventListener('click', onClickOutside, false);
document.addEventListener('keydown', escapeListener, false);
if (isAsync) {
container.click();
}
};
const close = () => {
if (typeof onCloseFn === 'function') {
onCloseFn();
}
document.removeEventListener('click', onClickOutside);
document.removeEventListener('keydown', escapeListener);
modal.innerHTML = '';
modal.className = '';
overlay.classList.add('hidden');
modalContainer.classList.add('hidden');
modal.style.display = 'none';
setTimeout(() => {
overlay.style.display = 'none';
modalContainer.style.display = 'none';
isOpening = false;
}, 400);
};
function onClickOutside(ev: Event) {
const notificationBar = document.querySelector('.snackbar');
if (
!modal?.contains(ev.target as Node) &&
!notificationBar?.contains(ev.target as Node) &&
!isOpening
) {
close();
}
isOpening = false;
}
const escapeListener = (event: KeyboardEvent) => {
if (event.key === 'Escape' && !(window as any).watchingEscape) {
close();
event.preventDefault();
}
};
return {
show,
close,
};
};