keyborg 2.326.0-canary.0 → 3.0.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.js CHANGED
@@ -1,506 +1,340 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __export = (target, all) => {
6
- for (var name in all)
7
- __defProp(target, name, { get: all[name], enumerable: true });
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
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
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
-
63
- // src/FocusEvent.ts
64
- var KEYBORG_FOCUSIN = "keyborg:focusin";
65
- var KEYBORG_FOCUSOUT = "keyborg:focusout";
66
- function canOverrideNativeFocus(win) {
67
- const HTMLElement = win.HTMLElement;
68
- const origFocus = HTMLElement.prototype.focus;
69
- let isCustomFocusCalled = false;
70
- HTMLElement.prototype.focus = function focus() {
71
- isCustomFocusCalled = true;
72
- };
73
- const btn = win.document.createElement("button");
74
- btn.focus();
75
- HTMLElement.prototype.focus = origFocus;
76
- return isCustomFocusCalled;
77
- }
78
- var _canOverrideNativeFocus = false;
12
+ //#endregion
13
+ //#region src/FocusEvent.mts
14
+ /*!
15
+ * Copyright (c) Microsoft Corporation. All rights reserved.
16
+ * Licensed under the MIT License.
17
+ */
18
+ const KEYBORG_FOCUSIN = "keyborg:focusin";
19
+ const KEYBORG_FOCUSOUT = "keyborg:focusout";
20
+ const FOCUS_IN_HANDLER = 0;
21
+ const FOCUS_OUT_HANDLER = 1;
22
+ const SHADOW_TARGETS = 2;
23
+ const LAST_FOCUSED_PROGRAMMATICALLY = 3;
24
+ /**
25
+ * Guarantees that the native `focus` will be used
26
+ */
79
27
  function nativeFocus(element) {
80
- const focus = element.focus;
81
- if (focus.__keyborgNativeFocus) {
82
- focus.__keyborgNativeFocus.call(element);
83
- } else {
84
- element.focus();
85
- }
28
+ const focus = element.focus;
29
+ if (focus.__keyborgNativeFocus) focus.__keyborgNativeFocus.call(element);
30
+ else element.focus();
86
31
  }
32
+ /**
33
+ * Overrides the native `focus` and setups the keyborg focus event
34
+ */
87
35
  function setupFocusEvent(win) {
88
- const kwin = win;
89
- if (!_canOverrideNativeFocus) {
90
- _canOverrideNativeFocus = canOverrideNativeFocus(kwin);
91
- }
92
- const origFocus = kwin.HTMLElement.prototype.focus;
93
- if (origFocus.__keyborgNativeFocus) {
94
- return;
95
- }
96
- kwin.HTMLElement.prototype.focus = focus;
97
- const shadowTargets = /* @__PURE__ */ new Set();
98
- const focusOutHandler = (e) => {
99
- const target = e.target;
100
- if (!target) {
101
- return;
102
- }
103
- const event = new CustomEvent(KEYBORG_FOCUSOUT, {
104
- cancelable: true,
105
- bubbles: true,
106
- // Allows the event to bubble past an open shadow root
107
- composed: true,
108
- detail: {
109
- originalEvent: e
110
- }
111
- });
112
- target.dispatchEvent(event);
113
- };
114
- const focusInHandler = (e) => {
115
- const target = e.target;
116
- if (!target) {
117
- return;
118
- }
119
- let node = e.composedPath()[0];
120
- const currentShadows = /* @__PURE__ */ new Set();
121
- while (node) {
122
- if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
123
- currentShadows.add(node);
124
- node = node.host;
125
- } else {
126
- node = node.parentNode;
127
- }
128
- }
129
- for (const shadowRootWeakRef of shadowTargets) {
130
- const shadowRoot = shadowRootWeakRef.deref();
131
- if (!shadowRoot || !currentShadows.has(shadowRoot)) {
132
- shadowTargets.delete(shadowRootWeakRef);
133
- if (shadowRoot) {
134
- shadowRoot.removeEventListener("focusin", focusInHandler, true);
135
- shadowRoot.removeEventListener("focusout", focusOutHandler, true);
136
- }
137
- }
138
- }
139
- onFocusIn(target, e.relatedTarget || void 0);
140
- };
141
- const onFocusIn = (target, relatedTarget, originalEvent) => {
142
- var _a;
143
- const shadowRoot = target.shadowRoot;
144
- if (shadowRoot) {
145
- for (const shadowRootWeakRef of shadowTargets) {
146
- if (shadowRootWeakRef.deref() === shadowRoot) {
147
- return;
148
- }
149
- }
150
- shadowRoot.addEventListener("focusin", focusInHandler, true);
151
- shadowRoot.addEventListener("focusout", focusOutHandler, true);
152
- shadowTargets.add(new WeakRefInstance(shadowRoot));
153
- return;
154
- }
155
- const details = {
156
- relatedTarget,
157
- originalEvent
158
- };
159
- const event = new CustomEvent(KEYBORG_FOCUSIN, {
160
- cancelable: true,
161
- bubbles: true,
162
- // Allows the event to bubble past an open shadow root
163
- composed: true,
164
- detail: details
165
- });
166
- event.details = details;
167
- if (_canOverrideNativeFocus || data.lastFocusedProgrammatically) {
168
- details.isFocusedProgrammatically = target === ((_a = data.lastFocusedProgrammatically) == null ? void 0 : _a.deref());
169
- data.lastFocusedProgrammatically = void 0;
170
- }
171
- target.dispatchEvent(event);
172
- };
173
- const data = kwin.__keyborgData = {
174
- focusInHandler,
175
- focusOutHandler,
176
- shadowTargets
177
- };
178
- kwin.document.addEventListener(
179
- "focusin",
180
- kwin.__keyborgData.focusInHandler,
181
- true
182
- );
183
- kwin.document.addEventListener(
184
- "focusout",
185
- kwin.__keyborgData.focusOutHandler,
186
- true
187
- );
188
- function focus() {
189
- const keyborgNativeFocusEvent = kwin.__keyborgData;
190
- if (keyborgNativeFocusEvent) {
191
- keyborgNativeFocusEvent.lastFocusedProgrammatically = new WeakRefInstance(
192
- this
193
- );
194
- }
195
- return origFocus.apply(this, arguments);
196
- }
197
- let activeElement = kwin.document.activeElement;
198
- while (activeElement && activeElement.shadowRoot) {
199
- onFocusIn(activeElement);
200
- activeElement = activeElement.shadowRoot.activeElement;
201
- }
202
- focus.__keyborgNativeFocus = origFocus;
36
+ const kwin = win;
37
+ const doc = kwin.document;
38
+ const proto = kwin.HTMLElement.prototype;
39
+ const origFocus = proto.focus;
40
+ if (origFocus.__keyborgNativeFocus) return;
41
+ proto.focus = focus;
42
+ const shadowTargets = /* @__PURE__ */ new Set();
43
+ const focusOutHandler = (e) => {
44
+ const target = e.target;
45
+ if (!target) return;
46
+ const event = new CustomEvent(KEYBORG_FOCUSOUT, {
47
+ cancelable: true,
48
+ bubbles: true,
49
+ composed: true,
50
+ detail: { originalEvent: e }
51
+ });
52
+ target.dispatchEvent(event);
53
+ };
54
+ const focusInHandler = (e) => {
55
+ const target = e.target;
56
+ if (!target) return;
57
+ let node = e.composedPath()[0];
58
+ const currentShadows = /* @__PURE__ */ new Set();
59
+ while (node) if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
60
+ currentShadows.add(node);
61
+ node = node.host;
62
+ } else node = node.parentNode;
63
+ for (const shadowRootWeakRef of shadowTargets) {
64
+ const shadowRoot = shadowRootWeakRef.deref();
65
+ if (!shadowRoot || !currentShadows.has(shadowRoot)) {
66
+ shadowTargets.delete(shadowRootWeakRef);
67
+ if (shadowRoot) {
68
+ removeEventListener(shadowRoot, "focusin", focusInHandler);
69
+ removeEventListener(shadowRoot, "focusout", focusOutHandler);
70
+ }
71
+ }
72
+ }
73
+ onFocusIn(target, e.relatedTarget || void 0);
74
+ };
75
+ const onFocusIn = (target, relatedTarget, originalEvent) => {
76
+ const shadowRoot = target.shadowRoot;
77
+ if (shadowRoot) {
78
+ /**
79
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=1512028
80
+ * focusin events don't bubble up through an open shadow root once focus is inside
81
+ * once focus moves into a shadow root - we drop the same focusin handler there
82
+ * keyborg's custom event will still bubble up since it is composed
83
+ * event handlers should be cleaned up once focus leaves the shadow root.
84
+ *
85
+ * When a focusin event is dispatched from a shadow root, its target is the shadow root parent.
86
+ * Each shadow root encounter requires a new capture listener.
87
+ * Why capture? - we want to follow the focus event in order or descending nested shadow roots
88
+ * When there are no more shadow root targets - dispatch the keyborg:focusin event
89
+ *
90
+ * 1. no focus event
91
+ * > document - capture listener ✅
92
+ * > shadow root 1
93
+ * > shadow root 2
94
+ * > shadow root 3
95
+ * > focused element
96
+ *
97
+ * 2. focus event received by document listener
98
+ * > document - capture listener ✅ (focus event here)
99
+ * > shadow root 1 - capture listener ✅
100
+ * > shadow root 2
101
+ * > shadow root 3
102
+ * > focused element
103
+ *
104
+ * 3. focus event received by root l1 listener
105
+ * > document - capture listener ✅
106
+ * > shadow root 1 - capture listener ✅ (focus event here)
107
+ * > shadow root 2 - capture listener ✅
108
+ * > shadow root 3
109
+ * > focused element
110
+ *
111
+ * 4. focus event received by root l2 listener
112
+ * > document - capture listener ✅
113
+ * > shadow root 1 - capture listener ✅
114
+ * > shadow root 2 - capture listener ✅ (focus event here)
115
+ * > shadow root 3 - capture listener ✅
116
+ * > focused element
117
+ *
118
+ * 5. focus event received by root l3 listener, no more shadow root targets
119
+ * > document - capture listener ✅
120
+ * > shadow root 1 - capture listener ✅
121
+ * > shadow root 2 - capture listener ✅
122
+ * > shadow root 3 - capture listener ✅ (focus event here)
123
+ * > focused element ✅ (no shadow root - dispatch keyborg event)
124
+ */
125
+ for (const shadowRootWeakRef of shadowTargets) if (shadowRootWeakRef.deref() === shadowRoot) return;
126
+ addEventListener(shadowRoot, "focusin", focusInHandler);
127
+ addEventListener(shadowRoot, "focusout", focusOutHandler);
128
+ shadowTargets.add(new WeakRef(shadowRoot));
129
+ return;
130
+ }
131
+ const details = {
132
+ relatedTarget,
133
+ originalEvent
134
+ };
135
+ const event = new CustomEvent(KEYBORG_FOCUSIN, {
136
+ cancelable: true,
137
+ bubbles: true,
138
+ composed: true,
139
+ detail: details
140
+ });
141
+ details.isFocusedProgrammatically = target === data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref();
142
+ data[LAST_FOCUSED_PROGRAMMATICALLY] = void 0;
143
+ target.dispatchEvent(event);
144
+ };
145
+ const data = [
146
+ focusInHandler,
147
+ focusOutHandler,
148
+ shadowTargets
149
+ ];
150
+ kwin.__keyborgData = data;
151
+ addEventListener(doc, "focusin", focusInHandler);
152
+ addEventListener(doc, "focusout", focusOutHandler);
153
+ function focus() {
154
+ const d = kwin.__keyborgData;
155
+ if (d) d[LAST_FOCUSED_PROGRAMMATICALLY] = new WeakRef(this);
156
+ return origFocus.apply(this, arguments);
157
+ }
158
+ let activeElement = doc.activeElement;
159
+ while (activeElement && activeElement.shadowRoot) {
160
+ onFocusIn(activeElement);
161
+ activeElement = activeElement.shadowRoot.activeElement;
162
+ }
163
+ focus.__keyborgNativeFocus = origFocus;
203
164
  }
165
+ /**
166
+ * Removes keyborg event listeners and custom focus override
167
+ * @param win The window that stores keyborg focus events
168
+ */
204
169
  function disposeFocusEvent(win) {
205
- const kwin = win;
206
- const proto = kwin.HTMLElement.prototype;
207
- const origFocus = proto.focus.__keyborgNativeFocus;
208
- const keyborgNativeFocusEvent = kwin.__keyborgData;
209
- if (keyborgNativeFocusEvent) {
210
- kwin.document.removeEventListener(
211
- "focusin",
212
- keyborgNativeFocusEvent.focusInHandler,
213
- true
214
- );
215
- kwin.document.removeEventListener(
216
- "focusout",
217
- keyborgNativeFocusEvent.focusOutHandler,
218
- true
219
- );
220
- for (const shadowRootWeakRef of keyborgNativeFocusEvent.shadowTargets) {
221
- const shadowRoot = shadowRootWeakRef.deref();
222
- if (shadowRoot) {
223
- shadowRoot.removeEventListener(
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
- }
170
+ const kwin = win;
171
+ const proto = kwin.HTMLElement.prototype;
172
+ const origFocus = proto.focus.__keyborgNativeFocus;
173
+ const data = kwin.__keyborgData;
174
+ if (data) {
175
+ const doc = kwin.document;
176
+ removeEventListener(doc, "focusin", data[FOCUS_IN_HANDLER]);
177
+ removeEventListener(doc, "focusout", data[FOCUS_OUT_HANDLER]);
178
+ for (const shadowRootWeakRef of data[SHADOW_TARGETS]) {
179
+ const shadowRoot = shadowRootWeakRef.deref();
180
+ if (shadowRoot) {
181
+ removeEventListener(shadowRoot, "focusin", data[FOCUS_IN_HANDLER]);
182
+ removeEventListener(shadowRoot, "focusout", data[FOCUS_OUT_HANDLER]);
183
+ }
184
+ }
185
+ data[SHADOW_TARGETS].clear();
186
+ delete kwin.__keyborgData;
187
+ }
188
+ if (origFocus) proto.focus = origFocus;
241
189
  }
190
+ /**
191
+ * @param win The window that stores keyborg focus events
192
+ * @returns The last element focused with element.focus()
193
+ */
242
194
  function getLastFocusedProgrammatically(win) {
243
- var _a;
244
- const keyborgNativeFocusEvent = win.__keyborgData;
245
- return keyborgNativeFocusEvent ? ((_a = keyborgNativeFocusEvent.lastFocusedProgrammatically) == null ? void 0 : _a.deref()) || null : void 0;
195
+ const data = win.__keyborgData;
196
+ return data ? data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref() || null : void 0;
246
197
  }
247
-
248
- // src/Keyborg.ts
249
- var _dismissTimeout = 500;
250
- var _lastId = 0;
251
- var KeyborgCore = class {
252
- constructor(win, props) {
253
- this._isNavigatingWithKeyboard_DO_NOT_USE = false;
254
- this._onFocusIn = (e) => {
255
- if (this._isMouseOrTouchUsedTimer) {
256
- return;
257
- }
258
- if (this.isNavigatingWithKeyboard) {
259
- return;
260
- }
261
- const details = e.detail;
262
- if (!details.relatedTarget) {
263
- return;
264
- }
265
- if (details.isFocusedProgrammatically || details.isFocusedProgrammatically === void 0) {
266
- return;
267
- }
268
- this.isNavigatingWithKeyboard = true;
269
- };
270
- this._onMouseDown = (e) => {
271
- if (e.buttons === 0 || e.clientX === 0 && e.clientY === 0 && e.screenX === 0 && e.screenY === 0) {
272
- return;
273
- }
274
- this._onMouseOrTouch();
275
- };
276
- this._onMouseOrTouch = () => {
277
- const win = this._win;
278
- if (win) {
279
- if (this._isMouseOrTouchUsedTimer) {
280
- win.clearTimeout(this._isMouseOrTouchUsedTimer);
281
- }
282
- this._isMouseOrTouchUsedTimer = win.setTimeout(() => {
283
- delete this._isMouseOrTouchUsedTimer;
284
- }, 1e3);
285
- }
286
- this.isNavigatingWithKeyboard = false;
287
- };
288
- this._onKeyDown = (e) => {
289
- const isNavigatingWithKeyboard = this.isNavigatingWithKeyboard;
290
- if (isNavigatingWithKeyboard) {
291
- if (this._shouldDismissKeyboardNavigation(e)) {
292
- this._scheduleDismiss();
293
- }
294
- } else {
295
- if (this._shouldTriggerKeyboardNavigation(e)) {
296
- this.isNavigatingWithKeyboard = true;
297
- }
298
- }
299
- };
300
- this.id = "c" + ++_lastId;
301
- this._win = win;
302
- const doc = win.document;
303
- if (props) {
304
- const triggerKeys = props.triggerKeys;
305
- const dismissKeys = props.dismissKeys;
306
- if (triggerKeys == null ? void 0 : triggerKeys.length) {
307
- this._triggerKeys = new Set(triggerKeys);
308
- }
309
- if (dismissKeys == null ? void 0 : dismissKeys.length) {
310
- this._dismissKeys = new Set(dismissKeys);
311
- }
312
- }
313
- doc.addEventListener(KEYBORG_FOCUSIN, this._onFocusIn, true);
314
- doc.addEventListener("mousedown", this._onMouseDown, true);
315
- win.addEventListener("keydown", this._onKeyDown, true);
316
- doc.addEventListener("touchstart", this._onMouseOrTouch, true);
317
- doc.addEventListener("touchend", this._onMouseOrTouch, true);
318
- doc.addEventListener("touchcancel", this._onMouseOrTouch, true);
319
- setupFocusEvent(win);
320
- }
321
- get isNavigatingWithKeyboard() {
322
- return this._isNavigatingWithKeyboard_DO_NOT_USE;
323
- }
324
- set isNavigatingWithKeyboard(val) {
325
- if (this._isNavigatingWithKeyboard_DO_NOT_USE !== val) {
326
- this._isNavigatingWithKeyboard_DO_NOT_USE = val;
327
- this.update();
328
- }
329
- }
330
- dispose() {
331
- const win = this._win;
332
- if (win) {
333
- if (this._isMouseOrTouchUsedTimer) {
334
- win.clearTimeout(this._isMouseOrTouchUsedTimer);
335
- this._isMouseOrTouchUsedTimer = void 0;
336
- }
337
- if (this._dismissTimer) {
338
- win.clearTimeout(this._dismissTimer);
339
- this._dismissTimer = void 0;
340
- }
341
- disposeFocusEvent(win);
342
- const doc = win.document;
343
- doc.removeEventListener(KEYBORG_FOCUSIN, this._onFocusIn, true);
344
- doc.removeEventListener("mousedown", this._onMouseDown, true);
345
- win.removeEventListener("keydown", this._onKeyDown, true);
346
- doc.removeEventListener("touchstart", this._onMouseOrTouch, true);
347
- doc.removeEventListener("touchend", this._onMouseOrTouch, true);
348
- doc.removeEventListener("touchcancel", this._onMouseOrTouch, true);
349
- delete this._win;
350
- }
351
- }
352
- isDisposed() {
353
- return !!this._win;
354
- }
355
- /**
356
- * Updates all keyborg instances with the keyboard navigation state
357
- */
358
- update() {
359
- var _a, _b;
360
- const keyborgs = (_b = (_a = this._win) == null ? void 0 : _a.__keyborg) == null ? void 0 : _b.refs;
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
- };
483
- function createKeyborg(win, props) {
484
- return Keyborg.create(win, props);
198
+ //#endregion
199
+ //#region src/Keyborg.mts
200
+ /*!
201
+ * Copyright (c) Microsoft Corporation. All rights reserved.
202
+ * Licensed under the MIT License.
203
+ */
204
+ let _lastId = 0;
205
+ function createKeyborgCore(targetWindow) {
206
+ let currentTargetWindow = targetWindow;
207
+ let isNavigating = false;
208
+ let isMouseOrTouchUsedTimer;
209
+ const broadcast = () => {
210
+ const refs = currentTargetWindow?.__keyborg?.refs;
211
+ if (refs) for (const id of Object.keys(refs)) refs[id]._cb.forEach((cb) => cb(isNavigating));
212
+ };
213
+ const setNavigating = (val) => {
214
+ if (isNavigating !== val) {
215
+ isNavigating = val;
216
+ broadcast();
217
+ }
218
+ };
219
+ const shouldTrigger = (e) => {
220
+ if (e.key === "Tab") return true;
221
+ const active = currentTargetWindow?.document.activeElement;
222
+ return !(active && (active.tagName === "INPUT" || active.tagName === "TEXTAREA" || active.isContentEditable));
223
+ };
224
+ const onFocusIn = (e) => {
225
+ if (isMouseOrTouchUsedTimer) return;
226
+ if (isNavigating) return;
227
+ const details = e.detail;
228
+ if (!details.relatedTarget) return;
229
+ if (details.isFocusedProgrammatically || details.isFocusedProgrammatically === void 0) return;
230
+ setNavigating(true);
231
+ };
232
+ const onMouseOrTouch = () => {
233
+ if (currentTargetWindow) {
234
+ if (isMouseOrTouchUsedTimer) currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);
235
+ isMouseOrTouchUsedTimer = currentTargetWindow.setTimeout(() => {
236
+ isMouseOrTouchUsedTimer = void 0;
237
+ }, 1e3);
238
+ }
239
+ setNavigating(false);
240
+ };
241
+ const onMouseDown = (e) => {
242
+ if (e.buttons === 0 || e.clientX === 0 && e.clientY === 0 && e.screenX === 0 && e.screenY === 0) return;
243
+ onMouseOrTouch();
244
+ };
245
+ const onKeyDown = (e) => {
246
+ if (!isNavigating && shouldTrigger(e)) setNavigating(true);
247
+ };
248
+ const targetDocument = targetWindow.document;
249
+ addEventListener(targetDocument, KEYBORG_FOCUSIN, onFocusIn);
250
+ addEventListener(targetDocument, "mousedown", onMouseDown);
251
+ addEventListener(targetWindow, "keydown", onKeyDown);
252
+ addEventListener(targetDocument, "touchstart", onMouseOrTouch);
253
+ addEventListener(targetDocument, "touchend", onMouseOrTouch);
254
+ addEventListener(targetDocument, "touchcancel", onMouseOrTouch);
255
+ setupFocusEvent(targetWindow);
256
+ const dispose = () => {
257
+ if (!currentTargetWindow) return;
258
+ if (isMouseOrTouchUsedTimer) {
259
+ currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);
260
+ isMouseOrTouchUsedTimer = void 0;
261
+ }
262
+ disposeFocusEvent(currentTargetWindow);
263
+ const targetDocument = currentTargetWindow.document;
264
+ removeEventListener(targetDocument, KEYBORG_FOCUSIN, onFocusIn);
265
+ removeEventListener(targetDocument, "mousedown", onMouseDown);
266
+ removeEventListener(currentTargetWindow, "keydown", onKeyDown);
267
+ removeEventListener(targetDocument, "touchstart", onMouseOrTouch);
268
+ removeEventListener(targetDocument, "touchend", onMouseOrTouch);
269
+ removeEventListener(targetDocument, "touchcancel", onMouseOrTouch);
270
+ currentTargetWindow = void 0;
271
+ };
272
+ return {
273
+ dispose,
274
+ get isNavigatingWithKeyboard() {
275
+ return isNavigating;
276
+ },
277
+ set isNavigatingWithKeyboard(val) {
278
+ setNavigating(val);
279
+ }
280
+ };
281
+ }
282
+ function createKeyborg(win) {
283
+ const kwin = win;
284
+ const id = "k" + ++_lastId;
285
+ let localWin = kwin;
286
+ let core;
287
+ const callbacks = [];
288
+ const existing = kwin.__keyborg;
289
+ if (existing) core = existing.core;
290
+ else core = createKeyborgCore(kwin);
291
+ const instance = {
292
+ isNavigatingWithKeyboard() {
293
+ return !!core?.isNavigatingWithKeyboard;
294
+ },
295
+ subscribe(callback) {
296
+ callbacks.push(callback);
297
+ },
298
+ unsubscribe(callback) {
299
+ const index = callbacks.indexOf(callback);
300
+ if (index >= 0) callbacks.splice(index, 1);
301
+ },
302
+ setVal(val) {
303
+ if (core) core.isNavigatingWithKeyboard = val;
304
+ },
305
+ _cb: callbacks,
306
+ dispose() {
307
+ const wkb = localWin?.__keyborg;
308
+ if (wkb?.refs[id]) {
309
+ delete wkb.refs[id];
310
+ if (Object.keys(wkb.refs).length === 0) {
311
+ wkb.core.dispose();
312
+ delete localWin.__keyborg;
313
+ }
314
+ } else if (process.env.NODE_ENV !== "production") console.error(`Keyborg instance ${id} is being disposed incorrectly.`);
315
+ callbacks.length = 0;
316
+ core = void 0;
317
+ localWin = void 0;
318
+ }
319
+ };
320
+ if (existing) existing.refs[id] = instance;
321
+ else kwin.__keyborg = {
322
+ core,
323
+ refs: { [id]: instance }
324
+ };
325
+ return instance;
485
326
  }
486
327
  function disposeKeyborg(instance) {
487
- Keyborg.dispose(instance);
328
+ instance.dispose();
488
329
  }
489
-
490
- // src/index.ts
491
- var version = "2.326.0-canary.0";
492
- // Annotate the CommonJS export names for ESM import in node:
493
- 0 && (module.exports = {
494
- KEYBORG_FOCUSIN,
495
- KEYBORG_FOCUSOUT,
496
- createKeyborg,
497
- disposeKeyborg,
498
- getLastFocusedProgrammatically,
499
- nativeFocus,
500
- version
501
- });
330
+ //#endregion
331
+ //#region src/index.mts
502
332
  /*!
503
- * Copyright (c) Microsoft Corporation. All rights reserved.
504
- * Licensed under the MIT License.
505
- */
333
+ * Copyright (c) Microsoft Corporation. All rights reserved.
334
+ * Licensed under the MIT License.
335
+ */
336
+ const version = "3.0.0";
337
+ //#endregion
338
+ export { KEYBORG_FOCUSIN, KEYBORG_FOCUSOUT, createKeyborg, disposeKeyborg, getLastFocusedProgrammatically, nativeFocus, version };
339
+
506
340
  //# sourceMappingURL=index.js.map