-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathevents.ts
More file actions
129 lines (109 loc) · 3.85 KB
/
events.ts
File metadata and controls
129 lines (109 loc) · 3.85 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
import { refreshActiveHighlight } from "./highlight";
import { emit } from "./emitter";
import { getState, setState } from "./state";
import { getConfig } from "./config";
import { getFocusableElements } from "./utils";
export function requireRefresh() {
const resizeTimeout = getState("__resizeTimeout");
if (resizeTimeout) {
window.cancelAnimationFrame(resizeTimeout);
}
setState("__resizeTimeout", window.requestAnimationFrame(refreshActiveHighlight));
}
function trapFocus(e: KeyboardEvent) {
const isActivated = getState("isInitialized");
if (!isActivated) {
return;
}
const isTabKey = e.key === "Tab" || e.keyCode === 9;
if (!isTabKey) {
return;
}
const activeElement = getState("__activeElement");
const popoverEl = getState("popover")?.wrapper;
const focusableEls = getFocusableElements([
...(popoverEl ? [popoverEl] : []),
...(activeElement ? [activeElement] : []),
]);
const firstFocusableEl = focusableEls[0];
const lastFocusableEl = focusableEls[focusableEls.length - 1];
e.preventDefault();
if (e.shiftKey) {
const previousFocusableEl =
focusableEls[focusableEls.indexOf(document.activeElement as HTMLElement) - 1] || lastFocusableEl;
previousFocusableEl?.focus();
} else {
const nextFocusableEl =
focusableEls[focusableEls.indexOf(document.activeElement as HTMLElement) + 1] || firstFocusableEl;
nextFocusableEl?.focus();
}
}
function onKeyup(e: KeyboardEvent) {
const allowKeyboardControl = getConfig("allowKeyboardControl") ?? true;
if (!allowKeyboardControl) {
return;
}
if (e.key === "Escape") {
emit("escapePress");
} else if (e.key === "Enter") {
emit("arrowRightPress");
} else if (e.key === "ArrowRight") {
emit("arrowRightPress");
} else if (e.key === "ArrowLeft") {
emit("arrowLeftPress");
}
}
/**
* Attaches click handler to the elements created by driver.js. It makes
* sure to give the listener the first chance to handle the event, and
* prevents all other pointer-events to make sure no external-library
* ever knows the click happened.
*
* @param {Element} element Element to listen for click events
* @param {(pointer: MouseEvent | PointerEvent) => void} listener Click handler
* @param {(target: HTMLElement) => boolean} shouldPreventDefault Whether to prevent default action i.e. link clicks etc
*/
export function onDriverClick(
element: Element,
listener: (pointer: MouseEvent | PointerEvent) => void,
shouldPreventDefault?: (target: HTMLElement) => boolean
) {
const listenerWrapper = (e: MouseEvent | PointerEvent, listener?: (pointer: MouseEvent | PointerEvent) => void) => {
const target = e.target as HTMLElement;
if (!element.contains(target)) {
return;
}
if (!shouldPreventDefault || shouldPreventDefault(target)) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
}
listener?.(e);
};
// We want to be the absolute first one to hear about the event
const useCapture = true;
// Events to disable
document.addEventListener("pointerdown", listenerWrapper, useCapture);
document.addEventListener("mousedown", listenerWrapper, useCapture);
document.addEventListener("pointerup", listenerWrapper, useCapture);
document.addEventListener("mouseup", listenerWrapper, useCapture);
// Actual click handler
document.addEventListener(
"click",
e => {
listenerWrapper(e, listener);
},
useCapture
);
}
export function initEvents() {
window.addEventListener("keyup", onKeyup, false);
window.addEventListener("keydown", trapFocus, false);
window.addEventListener("resize", requireRefresh);
window.addEventListener("scroll", requireRefresh);
}
export function destroyEvents() {
window.removeEventListener("keyup", onKeyup);
window.removeEventListener("resize", requireRefresh);
window.removeEventListener("scroll", requireRefresh);
}