-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathalerts.ts
117 lines (95 loc) · 3.08 KB
/
alerts.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
export type AlertOptions = {
key?: string;
duration?: number;
};
export default class AlertsElement extends HTMLElement {
public static duration: number = 10000;
private timeouts: WeakMap<HTMLElement, number> = new Map();
private index: number = 0;
public connectedCallback(): void {
if (!this.hasAttribute('role')) {
this.setAttribute('role', 'status');
}
if (!this.hasAttribute('aria-live')) {
this.setAttribute('aria-live', 'polite');
}
if (!this.hasAttribute('aria-relevant')) {
this.setAttribute('aria-relevant', 'additions');
}
for (const child of this.children) {
this.show(child as HTMLElement);
}
}
public show(el: HTMLElement, options: AlertOptions = {}) {
const key = options.key || el.dataset.key || String(this.index++);
this.dismiss(key);
el.dataset.key = key;
if (!this.contains(el)) {
this.append(el);
}
const duration = Number(
options.duration !== undefined
? options.duration
: el.dataset.duration || AlertsElement.duration
);
if (duration > 0) {
this.startTimeout(el, duration);
el.addEventListener('mouseenter', this.clearTimeout.bind(this, el));
el.addEventListener('focusin', this.clearTimeout.bind(this, el));
el.addEventListener(
'mouseleave',
this.startTimeout.bind(this, el, duration)
);
el.addEventListener(
'focusout',
this.startTimeout.bind(this, el, duration)
);
}
return key;
}
public dismiss(el: HTMLElement): void;
public dismiss(key: string): void;
public dismiss(elOrKey: HTMLElement | string): void {
if (typeof elOrKey === 'string') {
this.querySelectorAll<HTMLElement>(
`[data-key="${elOrKey}"]`
).forEach((el) => this.dismiss(el));
return;
}
elOrKey.remove();
this.clearTimeout(elOrKey);
}
public clear(): void {
Array.from(this.children).forEach((child) => {
this.dismiss(child as HTMLElement);
});
}
public speak(message: string): void {
const el = document.createElement('div');
Object.assign(el.style, {
clip: 'rect(0 0 0 0)',
clipPath: 'inset(50%)',
height: '1px',
overflow: 'hidden',
position: 'absolute',
whiteSpace: 'nowrap',
width: '1px',
});
el.textContent = message;
this.show(el);
}
private startTimeout(el: HTMLElement, duration: number) {
this.clearTimeout(el);
this.timeouts.set(
el,
window.setTimeout(() => {
this.dismiss(el);
}, duration)
);
}
private clearTimeout(el: HTMLElement) {
if (this.timeouts.has(el)) {
clearTimeout(this.timeouts.get(el));
}
}
}