keyborg 2.13.0-canary.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +394 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +71 -0
- package/dist/index.d.ts +40 -99
- package/dist/index.js +366 -486
- package/dist/index.js.map +1 -1
- package/dist/ts3.9/index.d.ts +14 -66
- package/package.json +34 -21
- package/dist/esm/index.js +0 -474
- package/dist/esm/index.js.map +0 -1
- package/dist/index.d.mts +0 -130
package/dist/index.js
CHANGED
|
@@ -1,506 +1,386 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
-
for (let key of __getOwnPropNames(from))
|
|
12
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
-
}
|
|
15
|
-
return to;
|
|
1
|
+
//#region src/dom.mts
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
const addEventListener = (target, type, handler) => {
|
|
7
|
+
target.addEventListener(type, handler, true);
|
|
16
8
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// src/index.ts
|
|
20
|
-
var src_exports = {};
|
|
21
|
-
__export(src_exports, {
|
|
22
|
-
KEYBORG_FOCUSIN: () => KEYBORG_FOCUSIN,
|
|
23
|
-
KEYBORG_FOCUSOUT: () => KEYBORG_FOCUSOUT,
|
|
24
|
-
createKeyborg: () => createKeyborg,
|
|
25
|
-
disposeKeyborg: () => disposeKeyborg,
|
|
26
|
-
getLastFocusedProgrammatically: () => getLastFocusedProgrammatically,
|
|
27
|
-
nativeFocus: () => nativeFocus,
|
|
28
|
-
version: () => version
|
|
29
|
-
});
|
|
30
|
-
module.exports = __toCommonJS(src_exports);
|
|
31
|
-
|
|
32
|
-
// src/WeakRefInstance.ts
|
|
33
|
-
var _canUseWeakRef = typeof WeakRef !== "undefined";
|
|
34
|
-
var WeakRefInstance = class {
|
|
35
|
-
constructor(instance) {
|
|
36
|
-
if (_canUseWeakRef && typeof instance === "object") {
|
|
37
|
-
this._weakRef = new WeakRef(instance);
|
|
38
|
-
} else {
|
|
39
|
-
this._instance = instance;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef/deref}
|
|
44
|
-
*/
|
|
45
|
-
deref() {
|
|
46
|
-
var _a, _b;
|
|
47
|
-
let instance;
|
|
48
|
-
if (this._weakRef) {
|
|
49
|
-
instance = (_a = this._weakRef) == null ? void 0 : _a.deref();
|
|
50
|
-
if (!instance) {
|
|
51
|
-
delete this._weakRef;
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
instance = this._instance;
|
|
55
|
-
if ((_b = instance == null ? void 0 : instance.isDisposed) == null ? void 0 : _b.call(instance)) {
|
|
56
|
-
delete this._instance;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return instance;
|
|
60
|
-
}
|
|
9
|
+
const removeEventListener = (target, type, handler) => {
|
|
10
|
+
target.removeEventListener(type, handler, true);
|
|
61
11
|
};
|
|
62
12
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/FocusEvent.mts
|
|
15
|
+
/*!
|
|
16
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
17
|
+
* Licensed under the MIT License.
|
|
18
|
+
*/
|
|
19
|
+
const KEYBORG_FOCUSIN = "keyborg:focusin";
|
|
20
|
+
const KEYBORG_FOCUSOUT = "keyborg:focusout";
|
|
21
|
+
const FOCUS_IN_HANDLER = 0;
|
|
22
|
+
const FOCUS_OUT_HANDLER = 1;
|
|
23
|
+
const SHADOW_TARGETS = 2;
|
|
24
|
+
const LAST_FOCUSED_PROGRAMMATICALLY = 3;
|
|
66
25
|
function canOverrideNativeFocus(win) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return isCustomFocusCalled;
|
|
26
|
+
const HTMLElement = win.HTMLElement;
|
|
27
|
+
const origFocus = HTMLElement.prototype.focus;
|
|
28
|
+
let isCustomFocusCalled = false;
|
|
29
|
+
HTMLElement.prototype.focus = function focus() {
|
|
30
|
+
isCustomFocusCalled = true;
|
|
31
|
+
};
|
|
32
|
+
win.document.createElement("button").focus();
|
|
33
|
+
HTMLElement.prototype.focus = origFocus;
|
|
34
|
+
return isCustomFocusCalled;
|
|
77
35
|
}
|
|
78
|
-
|
|
36
|
+
let _canOverrideNativeFocus = false;
|
|
37
|
+
/**
|
|
38
|
+
* Guarantees that the native `focus` will be used
|
|
39
|
+
*/
|
|
79
40
|
function nativeFocus(element) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
} else {
|
|
84
|
-
element.focus();
|
|
85
|
-
}
|
|
41
|
+
const focus = element.focus;
|
|
42
|
+
if (focus.__keyborgNativeFocus) focus.__keyborgNativeFocus.call(element);
|
|
43
|
+
else element.focus();
|
|
86
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Overrides the native `focus` and setups the keyborg focus event
|
|
47
|
+
*/
|
|
87
48
|
function setupFocusEvent(win) {
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
49
|
+
const kwin = win;
|
|
50
|
+
const doc = kwin.document;
|
|
51
|
+
const proto = kwin.HTMLElement.prototype;
|
|
52
|
+
if (!_canOverrideNativeFocus) _canOverrideNativeFocus = canOverrideNativeFocus(kwin);
|
|
53
|
+
const origFocus = proto.focus;
|
|
54
|
+
if (origFocus.__keyborgNativeFocus) return;
|
|
55
|
+
proto.focus = focus;
|
|
56
|
+
const shadowTargets = /* @__PURE__ */ new Set();
|
|
57
|
+
const focusOutHandler = (e) => {
|
|
58
|
+
const target = e.target;
|
|
59
|
+
if (!target) return;
|
|
60
|
+
const event = new CustomEvent(KEYBORG_FOCUSOUT, {
|
|
61
|
+
cancelable: true,
|
|
62
|
+
bubbles: true,
|
|
63
|
+
composed: true,
|
|
64
|
+
detail: { originalEvent: e }
|
|
65
|
+
});
|
|
66
|
+
target.dispatchEvent(event);
|
|
67
|
+
};
|
|
68
|
+
const focusInHandler = (e) => {
|
|
69
|
+
const target = e.target;
|
|
70
|
+
if (!target) return;
|
|
71
|
+
let node = e.composedPath()[0];
|
|
72
|
+
const currentShadows = /* @__PURE__ */ new Set();
|
|
73
|
+
while (node) if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
74
|
+
currentShadows.add(node);
|
|
75
|
+
node = node.host;
|
|
76
|
+
} else node = node.parentNode;
|
|
77
|
+
for (const shadowRootWeakRef of shadowTargets) {
|
|
78
|
+
const shadowRoot = shadowRootWeakRef.deref();
|
|
79
|
+
if (!shadowRoot || !currentShadows.has(shadowRoot)) {
|
|
80
|
+
shadowTargets.delete(shadowRootWeakRef);
|
|
81
|
+
if (shadowRoot) {
|
|
82
|
+
removeEventListener(shadowRoot, "focusin", focusInHandler);
|
|
83
|
+
removeEventListener(shadowRoot, "focusout", focusOutHandler);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
onFocusIn(target, e.relatedTarget || void 0);
|
|
88
|
+
};
|
|
89
|
+
const onFocusIn = (target, relatedTarget, originalEvent) => {
|
|
90
|
+
const shadowRoot = target.shadowRoot;
|
|
91
|
+
if (shadowRoot) {
|
|
92
|
+
/**
|
|
93
|
+
* https://bugs.chromium.org/p/chromium/issues/detail?id=1512028
|
|
94
|
+
* focusin events don't bubble up through an open shadow root once focus is inside
|
|
95
|
+
* once focus moves into a shadow root - we drop the same focusin handler there
|
|
96
|
+
* keyborg's custom event will still bubble up since it is composed
|
|
97
|
+
* event handlers should be cleaned up once focus leaves the shadow root.
|
|
98
|
+
*
|
|
99
|
+
* When a focusin event is dispatched from a shadow root, its target is the shadow root parent.
|
|
100
|
+
* Each shadow root encounter requires a new capture listener.
|
|
101
|
+
* Why capture? - we want to follow the focus event in order or descending nested shadow roots
|
|
102
|
+
* When there are no more shadow root targets - dispatch the keyborg:focusin event
|
|
103
|
+
*
|
|
104
|
+
* 1. no focus event
|
|
105
|
+
* > document - capture listener ✅
|
|
106
|
+
* > shadow root 1
|
|
107
|
+
* > shadow root 2
|
|
108
|
+
* > shadow root 3
|
|
109
|
+
* > focused element
|
|
110
|
+
*
|
|
111
|
+
* 2. focus event received by document listener
|
|
112
|
+
* > document - capture listener ✅ (focus event here)
|
|
113
|
+
* > shadow root 1 - capture listener ✅
|
|
114
|
+
* > shadow root 2
|
|
115
|
+
* > shadow root 3
|
|
116
|
+
* > focused element
|
|
117
|
+
*
|
|
118
|
+
* 3. focus event received by root l1 listener
|
|
119
|
+
* > document - capture listener ✅
|
|
120
|
+
* > shadow root 1 - capture listener ✅ (focus event here)
|
|
121
|
+
* > shadow root 2 - capture listener ✅
|
|
122
|
+
* > shadow root 3
|
|
123
|
+
* > focused element
|
|
124
|
+
*
|
|
125
|
+
* 4. focus event received by root l2 listener
|
|
126
|
+
* > document - capture listener ✅
|
|
127
|
+
* > shadow root 1 - capture listener ✅
|
|
128
|
+
* > shadow root 2 - capture listener ✅ (focus event here)
|
|
129
|
+
* > shadow root 3 - capture listener ✅
|
|
130
|
+
* > focused element
|
|
131
|
+
*
|
|
132
|
+
* 5. focus event received by root l3 listener, no more shadow root targets
|
|
133
|
+
* > document - capture listener ✅
|
|
134
|
+
* > shadow root 1 - capture listener ✅
|
|
135
|
+
* > shadow root 2 - capture listener ✅
|
|
136
|
+
* > shadow root 3 - capture listener ✅ (focus event here)
|
|
137
|
+
* > focused element ✅ (no shadow root - dispatch keyborg event)
|
|
138
|
+
*/
|
|
139
|
+
for (const shadowRootWeakRef of shadowTargets) if (shadowRootWeakRef.deref() === shadowRoot) return;
|
|
140
|
+
addEventListener(shadowRoot, "focusin", focusInHandler);
|
|
141
|
+
addEventListener(shadowRoot, "focusout", focusOutHandler);
|
|
142
|
+
shadowTargets.add(new WeakRef(shadowRoot));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const details = {
|
|
146
|
+
relatedTarget,
|
|
147
|
+
originalEvent
|
|
148
|
+
};
|
|
149
|
+
const event = new CustomEvent(KEYBORG_FOCUSIN, {
|
|
150
|
+
cancelable: true,
|
|
151
|
+
bubbles: true,
|
|
152
|
+
composed: true,
|
|
153
|
+
detail: details
|
|
154
|
+
});
|
|
155
|
+
event.details = details;
|
|
156
|
+
if (_canOverrideNativeFocus || data[LAST_FOCUSED_PROGRAMMATICALLY]) {
|
|
157
|
+
details.isFocusedProgrammatically = target === data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref();
|
|
158
|
+
data[LAST_FOCUSED_PROGRAMMATICALLY] = void 0;
|
|
159
|
+
}
|
|
160
|
+
target.dispatchEvent(event);
|
|
161
|
+
};
|
|
162
|
+
const data = [
|
|
163
|
+
focusInHandler,
|
|
164
|
+
focusOutHandler,
|
|
165
|
+
shadowTargets
|
|
166
|
+
];
|
|
167
|
+
kwin.__keyborgData = data;
|
|
168
|
+
addEventListener(doc, "focusin", focusInHandler);
|
|
169
|
+
addEventListener(doc, "focusout", focusOutHandler);
|
|
170
|
+
function focus() {
|
|
171
|
+
const d = kwin.__keyborgData;
|
|
172
|
+
if (d) d[LAST_FOCUSED_PROGRAMMATICALLY] = new WeakRef(this);
|
|
173
|
+
return origFocus.apply(this, arguments);
|
|
174
|
+
}
|
|
175
|
+
let activeElement = doc.activeElement;
|
|
176
|
+
while (activeElement && activeElement.shadowRoot) {
|
|
177
|
+
onFocusIn(activeElement);
|
|
178
|
+
activeElement = activeElement.shadowRoot.activeElement;
|
|
179
|
+
}
|
|
180
|
+
focus.__keyborgNativeFocus = origFocus;
|
|
203
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Removes keyborg event listeners and custom focus override
|
|
184
|
+
* @param win The window that stores keyborg focus events
|
|
185
|
+
*/
|
|
204
186
|
function disposeFocusEvent(win) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
"focusin",
|
|
225
|
-
keyborgNativeFocusEvent.focusInHandler,
|
|
226
|
-
true
|
|
227
|
-
);
|
|
228
|
-
shadowRoot.removeEventListener(
|
|
229
|
-
"focusout",
|
|
230
|
-
keyborgNativeFocusEvent.focusOutHandler,
|
|
231
|
-
true
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
keyborgNativeFocusEvent.shadowTargets.clear();
|
|
236
|
-
delete kwin.__keyborgData;
|
|
237
|
-
}
|
|
238
|
-
if (origFocus) {
|
|
239
|
-
proto.focus = origFocus;
|
|
240
|
-
}
|
|
187
|
+
const kwin = win;
|
|
188
|
+
const proto = kwin.HTMLElement.prototype;
|
|
189
|
+
const origFocus = proto.focus.__keyborgNativeFocus;
|
|
190
|
+
const data = kwin.__keyborgData;
|
|
191
|
+
if (data) {
|
|
192
|
+
const doc = kwin.document;
|
|
193
|
+
removeEventListener(doc, "focusin", data[FOCUS_IN_HANDLER]);
|
|
194
|
+
removeEventListener(doc, "focusout", data[FOCUS_OUT_HANDLER]);
|
|
195
|
+
for (const shadowRootWeakRef of data[SHADOW_TARGETS]) {
|
|
196
|
+
const shadowRoot = shadowRootWeakRef.deref();
|
|
197
|
+
if (shadowRoot) {
|
|
198
|
+
removeEventListener(shadowRoot, "focusin", data[FOCUS_IN_HANDLER]);
|
|
199
|
+
removeEventListener(shadowRoot, "focusout", data[FOCUS_OUT_HANDLER]);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
data[SHADOW_TARGETS].clear();
|
|
203
|
+
delete kwin.__keyborgData;
|
|
204
|
+
}
|
|
205
|
+
if (origFocus) proto.focus = origFocus;
|
|
241
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* @param win The window that stores keyborg focus events
|
|
209
|
+
* @returns The last element focused with element.focus()
|
|
210
|
+
*/
|
|
242
211
|
function getLastFocusedProgrammatically(win) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return keyborgNativeFocusEvent ? ((_a = keyborgNativeFocusEvent.lastFocusedProgrammatically) == null ? void 0 : _a.deref()) || null : void 0;
|
|
212
|
+
const data = win.__keyborgData;
|
|
213
|
+
return data ? data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref() || null : void 0;
|
|
246
214
|
}
|
|
247
215
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (keyborgs) {
|
|
362
|
-
for (const id of Object.keys(keyborgs)) {
|
|
363
|
-
Keyborg.update(keyborgs[id], this.isNavigatingWithKeyboard);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* @returns whether the keyboard event should trigger keyboard navigation mode
|
|
369
|
-
*/
|
|
370
|
-
_shouldTriggerKeyboardNavigation(e) {
|
|
371
|
-
var _a;
|
|
372
|
-
if (e.key === "Tab") {
|
|
373
|
-
return true;
|
|
374
|
-
}
|
|
375
|
-
const activeElement = (_a = this._win) == null ? void 0 : _a.document.activeElement;
|
|
376
|
-
const isTriggerKey = !this._triggerKeys || this._triggerKeys.has(e.keyCode);
|
|
377
|
-
const isEditable = activeElement && (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || activeElement.isContentEditable);
|
|
378
|
-
return isTriggerKey && !isEditable;
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* @returns whether the keyboard event should dismiss keyboard navigation mode
|
|
382
|
-
*/
|
|
383
|
-
_shouldDismissKeyboardNavigation(e) {
|
|
384
|
-
var _a;
|
|
385
|
-
return (_a = this._dismissKeys) == null ? void 0 : _a.has(e.keyCode);
|
|
386
|
-
}
|
|
387
|
-
_scheduleDismiss() {
|
|
388
|
-
const win = this._win;
|
|
389
|
-
if (win) {
|
|
390
|
-
if (this._dismissTimer) {
|
|
391
|
-
win.clearTimeout(this._dismissTimer);
|
|
392
|
-
this._dismissTimer = void 0;
|
|
393
|
-
}
|
|
394
|
-
const was = win.document.activeElement;
|
|
395
|
-
this._dismissTimer = win.setTimeout(() => {
|
|
396
|
-
this._dismissTimer = void 0;
|
|
397
|
-
const cur = win.document.activeElement;
|
|
398
|
-
if (was && cur && was === cur) {
|
|
399
|
-
this.isNavigatingWithKeyboard = false;
|
|
400
|
-
}
|
|
401
|
-
}, _dismissTimeout);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
var Keyborg = class _Keyborg {
|
|
406
|
-
constructor(win, props) {
|
|
407
|
-
this._cb = [];
|
|
408
|
-
this._id = "k" + ++_lastId;
|
|
409
|
-
this._win = win;
|
|
410
|
-
const current = win.__keyborg;
|
|
411
|
-
if (current) {
|
|
412
|
-
this._core = current.core;
|
|
413
|
-
current.refs[this._id] = this;
|
|
414
|
-
} else {
|
|
415
|
-
this._core = new KeyborgCore(win, props);
|
|
416
|
-
win.__keyborg = {
|
|
417
|
-
core: this._core,
|
|
418
|
-
refs: { [this._id]: this }
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
static create(win, props) {
|
|
423
|
-
return new _Keyborg(win, props);
|
|
424
|
-
}
|
|
425
|
-
static dispose(instance) {
|
|
426
|
-
instance.dispose();
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Updates all subscribed callbacks with the keyboard navigation state
|
|
430
|
-
*/
|
|
431
|
-
static update(instance, isNavigatingWithKeyboard) {
|
|
432
|
-
instance._cb.forEach((callback) => callback(isNavigatingWithKeyboard));
|
|
433
|
-
}
|
|
434
|
-
dispose() {
|
|
435
|
-
var _a;
|
|
436
|
-
const current = (_a = this._win) == null ? void 0 : _a.__keyborg;
|
|
437
|
-
if (current == null ? void 0 : current.refs[this._id]) {
|
|
438
|
-
delete current.refs[this._id];
|
|
439
|
-
if (Object.keys(current.refs).length === 0) {
|
|
440
|
-
current.core.dispose();
|
|
441
|
-
delete this._win.__keyborg;
|
|
442
|
-
}
|
|
443
|
-
} else if (process.env.NODE_ENV !== "production") {
|
|
444
|
-
console.error(
|
|
445
|
-
`Keyborg instance ${this._id} is being disposed incorrectly.`
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
this._cb = [];
|
|
449
|
-
delete this._core;
|
|
450
|
-
delete this._win;
|
|
451
|
-
}
|
|
452
|
-
/**
|
|
453
|
-
* @returns Whether the user is navigating with keyboard
|
|
454
|
-
*/
|
|
455
|
-
isNavigatingWithKeyboard() {
|
|
456
|
-
var _a;
|
|
457
|
-
return !!((_a = this._core) == null ? void 0 : _a.isNavigatingWithKeyboard);
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* @param callback - Called when the keyboard navigation state changes
|
|
461
|
-
*/
|
|
462
|
-
subscribe(callback) {
|
|
463
|
-
this._cb.push(callback);
|
|
464
|
-
}
|
|
465
|
-
/**
|
|
466
|
-
* @param callback - Registered with subscribe
|
|
467
|
-
*/
|
|
468
|
-
unsubscribe(callback) {
|
|
469
|
-
const index = this._cb.indexOf(callback);
|
|
470
|
-
if (index >= 0) {
|
|
471
|
-
this._cb.splice(index, 1);
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Manually set the keyboard navigtion state
|
|
476
|
-
*/
|
|
477
|
-
setVal(isNavigatingWithKeyboard) {
|
|
478
|
-
if (this._core) {
|
|
479
|
-
this._core.isNavigatingWithKeyboard = isNavigatingWithKeyboard;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
};
|
|
216
|
+
//#endregion
|
|
217
|
+
//#region src/Keyborg.mts
|
|
218
|
+
/*!
|
|
219
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
220
|
+
* Licensed under the MIT License.
|
|
221
|
+
*/
|
|
222
|
+
const _dismissTimeout = 500;
|
|
223
|
+
let _lastId = 0;
|
|
224
|
+
function createKeyborgCore(targetWindow, props) {
|
|
225
|
+
let currentTargetWindow = targetWindow;
|
|
226
|
+
let isNavigating = false;
|
|
227
|
+
let isMouseOrTouchUsedTimer;
|
|
228
|
+
let dismissTimer;
|
|
229
|
+
let triggerKeys;
|
|
230
|
+
let dismissKeys;
|
|
231
|
+
if (props) {
|
|
232
|
+
if (props.triggerKeys?.length) triggerKeys = new Set(props.triggerKeys);
|
|
233
|
+
if (props.dismissKeys?.length) dismissKeys = new Set(props.dismissKeys);
|
|
234
|
+
}
|
|
235
|
+
const broadcast = () => {
|
|
236
|
+
const refs = currentTargetWindow?.__keyborg?.refs;
|
|
237
|
+
if (refs) for (const id of Object.keys(refs)) refs[id]._notify(isNavigating);
|
|
238
|
+
};
|
|
239
|
+
const setNavigating = (val) => {
|
|
240
|
+
if (isNavigating !== val) {
|
|
241
|
+
isNavigating = val;
|
|
242
|
+
broadcast();
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
const shouldTrigger = (e) => {
|
|
246
|
+
if (e.key === "Tab") return true;
|
|
247
|
+
const active = currentTargetWindow?.document.activeElement;
|
|
248
|
+
const isTriggerKey = !triggerKeys || triggerKeys.has(e.keyCode);
|
|
249
|
+
const isEditable = active && (active.tagName === "INPUT" || active.tagName === "TEXTAREA" || active.isContentEditable);
|
|
250
|
+
return isTriggerKey && !isEditable;
|
|
251
|
+
};
|
|
252
|
+
const shouldDismiss = (e) => {
|
|
253
|
+
return !!dismissKeys?.has(e.keyCode);
|
|
254
|
+
};
|
|
255
|
+
const scheduleDismiss = () => {
|
|
256
|
+
const targetWindow = currentTargetWindow;
|
|
257
|
+
if (!targetWindow) return;
|
|
258
|
+
if (dismissTimer) {
|
|
259
|
+
targetWindow.clearTimeout(dismissTimer);
|
|
260
|
+
dismissTimer = void 0;
|
|
261
|
+
}
|
|
262
|
+
const previousActiveElement = targetWindow.document.activeElement;
|
|
263
|
+
dismissTimer = targetWindow.setTimeout(() => {
|
|
264
|
+
dismissTimer = void 0;
|
|
265
|
+
const currentActiveElement = targetWindow.document.activeElement;
|
|
266
|
+
if (previousActiveElement && currentActiveElement && previousActiveElement === currentActiveElement) setNavigating(false);
|
|
267
|
+
}, _dismissTimeout);
|
|
268
|
+
};
|
|
269
|
+
const onFocusIn = (e) => {
|
|
270
|
+
if (isMouseOrTouchUsedTimer) return;
|
|
271
|
+
if (isNavigating) return;
|
|
272
|
+
const details = e.detail;
|
|
273
|
+
if (!details.relatedTarget) return;
|
|
274
|
+
if (details.isFocusedProgrammatically || details.isFocusedProgrammatically === void 0) return;
|
|
275
|
+
setNavigating(true);
|
|
276
|
+
};
|
|
277
|
+
const onMouseOrTouch = () => {
|
|
278
|
+
if (currentTargetWindow) {
|
|
279
|
+
if (isMouseOrTouchUsedTimer) currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);
|
|
280
|
+
isMouseOrTouchUsedTimer = currentTargetWindow.setTimeout(() => {
|
|
281
|
+
isMouseOrTouchUsedTimer = void 0;
|
|
282
|
+
}, 1e3);
|
|
283
|
+
}
|
|
284
|
+
setNavigating(false);
|
|
285
|
+
};
|
|
286
|
+
const onMouseDown = (e) => {
|
|
287
|
+
if (e.buttons === 0 || e.clientX === 0 && e.clientY === 0 && e.screenX === 0 && e.screenY === 0) return;
|
|
288
|
+
onMouseOrTouch();
|
|
289
|
+
};
|
|
290
|
+
const onKeyDown = (e) => {
|
|
291
|
+
if (isNavigating) {
|
|
292
|
+
if (shouldDismiss(e)) scheduleDismiss();
|
|
293
|
+
} else if (shouldTrigger(e)) setNavigating(true);
|
|
294
|
+
};
|
|
295
|
+
const targetDocument = targetWindow.document;
|
|
296
|
+
addEventListener(targetDocument, KEYBORG_FOCUSIN, onFocusIn);
|
|
297
|
+
addEventListener(targetDocument, "mousedown", onMouseDown);
|
|
298
|
+
addEventListener(targetWindow, "keydown", onKeyDown);
|
|
299
|
+
addEventListener(targetDocument, "touchstart", onMouseOrTouch);
|
|
300
|
+
addEventListener(targetDocument, "touchend", onMouseOrTouch);
|
|
301
|
+
addEventListener(targetDocument, "touchcancel", onMouseOrTouch);
|
|
302
|
+
setupFocusEvent(targetWindow);
|
|
303
|
+
const dispose = () => {
|
|
304
|
+
if (!currentTargetWindow) return;
|
|
305
|
+
if (isMouseOrTouchUsedTimer) {
|
|
306
|
+
currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);
|
|
307
|
+
isMouseOrTouchUsedTimer = void 0;
|
|
308
|
+
}
|
|
309
|
+
if (dismissTimer) {
|
|
310
|
+
currentTargetWindow.clearTimeout(dismissTimer);
|
|
311
|
+
dismissTimer = void 0;
|
|
312
|
+
}
|
|
313
|
+
disposeFocusEvent(currentTargetWindow);
|
|
314
|
+
const targetDocument = currentTargetWindow.document;
|
|
315
|
+
removeEventListener(targetDocument, KEYBORG_FOCUSIN, onFocusIn);
|
|
316
|
+
removeEventListener(targetDocument, "mousedown", onMouseDown);
|
|
317
|
+
removeEventListener(currentTargetWindow, "keydown", onKeyDown);
|
|
318
|
+
removeEventListener(targetDocument, "touchstart", onMouseOrTouch);
|
|
319
|
+
removeEventListener(targetDocument, "touchend", onMouseOrTouch);
|
|
320
|
+
removeEventListener(targetDocument, "touchcancel", onMouseOrTouch);
|
|
321
|
+
currentTargetWindow = void 0;
|
|
322
|
+
};
|
|
323
|
+
return {
|
|
324
|
+
dispose,
|
|
325
|
+
getNavigating: () => isNavigating,
|
|
326
|
+
setNavigating
|
|
327
|
+
};
|
|
328
|
+
}
|
|
483
329
|
function createKeyborg(win, props) {
|
|
484
|
-
|
|
330
|
+
const kwin = win;
|
|
331
|
+
const id = "k" + ++_lastId;
|
|
332
|
+
let localWin = kwin;
|
|
333
|
+
let core;
|
|
334
|
+
let callbacks = [];
|
|
335
|
+
const existing = kwin.__keyborg;
|
|
336
|
+
if (existing) core = existing.core;
|
|
337
|
+
else core = createKeyborgCore(kwin, props);
|
|
338
|
+
const instance = {
|
|
339
|
+
isNavigatingWithKeyboard() {
|
|
340
|
+
return !!core?.getNavigating();
|
|
341
|
+
},
|
|
342
|
+
subscribe(callback) {
|
|
343
|
+
callbacks.push(callback);
|
|
344
|
+
},
|
|
345
|
+
unsubscribe(callback) {
|
|
346
|
+
const index = callbacks.indexOf(callback);
|
|
347
|
+
if (index >= 0) callbacks.splice(index, 1);
|
|
348
|
+
},
|
|
349
|
+
setVal(val) {
|
|
350
|
+
core?.setNavigating(val);
|
|
351
|
+
},
|
|
352
|
+
_notify(val) {
|
|
353
|
+
callbacks.forEach((cb) => cb(val));
|
|
354
|
+
},
|
|
355
|
+
_dispose() {
|
|
356
|
+
const wkb = localWin?.__keyborg;
|
|
357
|
+
if (wkb?.refs[id]) {
|
|
358
|
+
delete wkb.refs[id];
|
|
359
|
+
if (Object.keys(wkb.refs).length === 0) {
|
|
360
|
+
wkb.core.dispose();
|
|
361
|
+
delete localWin.__keyborg;
|
|
362
|
+
}
|
|
363
|
+
} else if (process.env.NODE_ENV !== "production") console.error(`Keyborg instance ${id} is being disposed incorrectly.`);
|
|
364
|
+
callbacks = [];
|
|
365
|
+
core = void 0;
|
|
366
|
+
localWin = void 0;
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
if (existing) existing.refs[id] = instance;
|
|
370
|
+
else kwin.__keyborg = {
|
|
371
|
+
core,
|
|
372
|
+
refs: { [id]: instance }
|
|
373
|
+
};
|
|
374
|
+
return instance;
|
|
485
375
|
}
|
|
486
376
|
function disposeKeyborg(instance) {
|
|
487
|
-
|
|
377
|
+
instance._dispose();
|
|
488
378
|
}
|
|
489
379
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
createKeyborg,
|
|
497
|
-
disposeKeyborg,
|
|
498
|
-
getLastFocusedProgrammatically,
|
|
499
|
-
nativeFocus,
|
|
500
|
-
version
|
|
501
|
-
});
|
|
502
|
-
/*!
|
|
503
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
504
|
-
* Licensed under the MIT License.
|
|
505
|
-
*/
|
|
380
|
+
//#endregion
|
|
381
|
+
//#region src/index.mts
|
|
382
|
+
const version = "2.14.0";
|
|
383
|
+
|
|
384
|
+
//#endregion
|
|
385
|
+
export { KEYBORG_FOCUSIN, KEYBORG_FOCUSOUT, createKeyborg, disposeKeyborg, getLastFocusedProgrammatically, nativeFocus, version };
|
|
506
386
|
//# sourceMappingURL=index.js.map
|