keyborg 2.14.0 → 2.14.1
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 +15 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +15 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -236,7 +236,7 @@ function createKeyborgCore(targetWindow, props) {
|
|
|
236
236
|
}
|
|
237
237
|
const broadcast = () => {
|
|
238
238
|
const refs = currentTargetWindow?.__keyborg?.refs;
|
|
239
|
-
if (refs) for (const id of Object.keys(refs)) refs[id].
|
|
239
|
+
if (refs) for (const id of Object.keys(refs)) refs[id]._cb.forEach((cb) => cb(isNavigating));
|
|
240
240
|
};
|
|
241
241
|
const setNavigating = (val) => {
|
|
242
242
|
if (isNavigating !== val) {
|
|
@@ -324,8 +324,12 @@ function createKeyborgCore(targetWindow, props) {
|
|
|
324
324
|
};
|
|
325
325
|
return {
|
|
326
326
|
dispose,
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
get isNavigatingWithKeyboard() {
|
|
328
|
+
return isNavigating;
|
|
329
|
+
},
|
|
330
|
+
set isNavigatingWithKeyboard(val) {
|
|
331
|
+
setNavigating(val);
|
|
332
|
+
}
|
|
329
333
|
};
|
|
330
334
|
}
|
|
331
335
|
function createKeyborg(win, props) {
|
|
@@ -333,13 +337,13 @@ function createKeyborg(win, props) {
|
|
|
333
337
|
const id = "k" + ++_lastId;
|
|
334
338
|
let localWin = kwin;
|
|
335
339
|
let core;
|
|
336
|
-
|
|
340
|
+
const callbacks = [];
|
|
337
341
|
const existing = kwin.__keyborg;
|
|
338
342
|
if (existing) core = existing.core;
|
|
339
343
|
else core = createKeyborgCore(kwin, props);
|
|
340
344
|
const instance = {
|
|
341
345
|
isNavigatingWithKeyboard() {
|
|
342
|
-
return !!core?.
|
|
346
|
+
return !!core?.isNavigatingWithKeyboard;
|
|
343
347
|
},
|
|
344
348
|
subscribe(callback) {
|
|
345
349
|
callbacks.push(callback);
|
|
@@ -349,12 +353,10 @@ function createKeyborg(win, props) {
|
|
|
349
353
|
if (index >= 0) callbacks.splice(index, 1);
|
|
350
354
|
},
|
|
351
355
|
setVal(val) {
|
|
352
|
-
core
|
|
353
|
-
},
|
|
354
|
-
_notify(val) {
|
|
355
|
-
callbacks.forEach((cb) => cb(val));
|
|
356
|
+
if (core) core.isNavigatingWithKeyboard = val;
|
|
356
357
|
},
|
|
357
|
-
|
|
358
|
+
_cb: callbacks,
|
|
359
|
+
dispose() {
|
|
358
360
|
const wkb = localWin?.__keyborg;
|
|
359
361
|
if (wkb?.refs[id]) {
|
|
360
362
|
delete wkb.refs[id];
|
|
@@ -363,7 +365,7 @@ function createKeyborg(win, props) {
|
|
|
363
365
|
delete localWin.__keyborg;
|
|
364
366
|
}
|
|
365
367
|
} else if (process.env.NODE_ENV !== "production") console.error(`Keyborg instance ${id} is being disposed incorrectly.`);
|
|
366
|
-
callbacks =
|
|
368
|
+
callbacks.length = 0;
|
|
367
369
|
core = void 0;
|
|
368
370
|
localWin = void 0;
|
|
369
371
|
}
|
|
@@ -376,12 +378,12 @@ function createKeyborg(win, props) {
|
|
|
376
378
|
return instance;
|
|
377
379
|
}
|
|
378
380
|
function disposeKeyborg(instance) {
|
|
379
|
-
instance.
|
|
381
|
+
instance.dispose();
|
|
380
382
|
}
|
|
381
383
|
|
|
382
384
|
//#endregion
|
|
383
385
|
//#region src/index.mts
|
|
384
|
-
const version = "2.14.
|
|
386
|
+
const version = "2.14.1";
|
|
385
387
|
|
|
386
388
|
//#endregion
|
|
387
389
|
exports.KEYBORG_FOCUSIN = KEYBORG_FOCUSIN;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/dom.mts","../src/FocusEvent.mts","../src/Keyborg.mts","../src/index.mts"],"sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// All keyborg listeners use the capture phase; centralizing the calls lets the\n// minifier collapse the repeated DOM method names into a single short-named\n// import binding.\nexport const addEventListener = (\n target: EventTarget,\n type: string,\n handler: EventListener,\n): void => {\n target.addEventListener(type, handler, true);\n};\n\nexport const removeEventListener = (\n target: EventTarget,\n type: string,\n handler: EventListener,\n): void => {\n target.removeEventListener(type, handler, true);\n};\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { addEventListener, removeEventListener } from \"./dom.mts\";\n\nexport const KEYBORG_FOCUSIN = \"keyborg:focusin\";\nexport const KEYBORG_FOCUSOUT = \"keyborg:focusout\";\n\ninterface KeyborgFocus {\n /**\n * This is the native `focus` function that is retained so that it can be restored when keyborg is disposed\n */\n __keyborgNativeFocus?: (options?: FocusOptions | undefined) => void;\n}\n\n// Internal data stored on `window.__keyborgData` as a tuple. Nothing outside\n// this module reads these slots, so a tuple drops the property-name strings\n// from the minified output — the indexes below inline as numeric literals.\nconst FOCUS_IN_HANDLER = 0;\nconst FOCUS_OUT_HANDLER = 1;\nconst SHADOW_TARGETS = 2;\nconst LAST_FOCUSED_PROGRAMMATICALLY = 3;\ntype KeyborgFocusEventData = [\n (e: FocusEvent) => void,\n (e: FocusEvent) => void,\n Set<WeakRef<ShadowRoot>>,\n WeakRef<HTMLElement>?,\n];\n\n/**\n * Extends the global window with keyborg focus event data\n */\ninterface WindowWithKeyborgFocusEvent extends Window {\n HTMLElement: typeof HTMLElement;\n __keyborgData?: KeyborgFocusEventData;\n}\n\nfunction canOverrideNativeFocus(win: Window): boolean {\n const HTMLElement = (win as WindowWithKeyborgFocusEvent).HTMLElement;\n const origFocus = HTMLElement.prototype.focus;\n\n let isCustomFocusCalled = false;\n\n HTMLElement.prototype.focus = function focus(): void {\n isCustomFocusCalled = true;\n };\n\n const btn = win.document.createElement(\"button\");\n\n btn.focus();\n\n HTMLElement.prototype.focus = origFocus;\n\n return isCustomFocusCalled;\n}\n\nlet _canOverrideNativeFocus = false;\n\nexport interface KeyborgFocusInEventDetails {\n relatedTarget?: HTMLElement;\n isFocusedProgrammatically?: boolean;\n originalEvent?: FocusEvent;\n}\n\nexport interface KeyborgFocusInEvent extends CustomEvent<KeyborgFocusInEventDetails> {\n /**\n * @deprecated - used `event.detail`\n */\n details?: KeyborgFocusInEventDetails;\n}\n\nexport interface KeyborgFocusOutEventDetails {\n originalEvent: FocusEvent;\n}\n\nexport type KeyborgFocusOutEvent = CustomEvent<KeyborgFocusOutEventDetails>;\n\n/**\n * Guarantees that the native `focus` will be used\n */\nexport function nativeFocus(element: HTMLElement): void {\n const focus = element.focus as KeyborgFocus;\n\n if (focus.__keyborgNativeFocus) {\n focus.__keyborgNativeFocus.call(element);\n } else {\n element.focus();\n }\n}\n\n/**\n * Overrides the native `focus` and setups the keyborg focus event\n */\nexport function setupFocusEvent(win: Window): void {\n const kwin = win as WindowWithKeyborgFocusEvent;\n const doc = kwin.document;\n const proto = kwin.HTMLElement.prototype;\n\n if (!_canOverrideNativeFocus) {\n _canOverrideNativeFocus = canOverrideNativeFocus(kwin);\n }\n\n const origFocus = proto.focus;\n\n if ((origFocus as KeyborgFocus).__keyborgNativeFocus) {\n // Already set up.\n return;\n }\n\n proto.focus = focus;\n\n const shadowTargets: Set<WeakRef<ShadowRoot>> = new Set();\n\n const focusOutHandler = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n\n if (!target) {\n return;\n }\n\n const event: KeyborgFocusOutEvent = new CustomEvent(KEYBORG_FOCUSOUT, {\n cancelable: true,\n bubbles: true,\n // Allows the event to bubble past an open shadow root\n composed: true,\n detail: {\n originalEvent: e,\n },\n });\n\n target.dispatchEvent(event);\n };\n\n const focusInHandler = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n\n if (!target) {\n return;\n }\n\n let node: Node | null | undefined = e.composedPath()[0] as\n | Node\n | null\n | undefined;\n\n const currentShadows: Set<ShadowRoot> = new Set();\n\n while (node) {\n if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\n currentShadows.add(node as ShadowRoot);\n node = (node as ShadowRoot).host;\n } else {\n node = node.parentNode;\n }\n }\n\n for (const shadowRootWeakRef of shadowTargets) {\n const shadowRoot = shadowRootWeakRef.deref();\n\n if (!shadowRoot || !currentShadows.has(shadowRoot)) {\n shadowTargets.delete(shadowRootWeakRef);\n\n if (shadowRoot) {\n removeEventListener(shadowRoot, \"focusin\", focusInHandler);\n removeEventListener(shadowRoot, \"focusout\", focusOutHandler);\n }\n }\n }\n\n onFocusIn(target, (e.relatedTarget as HTMLElement | null) || undefined);\n };\n\n const onFocusIn = (\n target: Element,\n relatedTarget?: HTMLElement,\n originalEvent?: FocusEvent,\n ) => {\n const shadowRoot = target.shadowRoot;\n\n if (shadowRoot) {\n /**\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1512028\n * focusin events don't bubble up through an open shadow root once focus is inside\n * once focus moves into a shadow root - we drop the same focusin handler there\n * keyborg's custom event will still bubble up since it is composed\n * event handlers should be cleaned up once focus leaves the shadow root.\n *\n * When a focusin event is dispatched from a shadow root, its target is the shadow root parent.\n * Each shadow root encounter requires a new capture listener.\n * Why capture? - we want to follow the focus event in order or descending nested shadow roots\n * When there are no more shadow root targets - dispatch the keyborg:focusin event\n *\n * 1. no focus event\n * > document - capture listener ✅\n * > shadow root 1\n * > shadow root 2\n * > shadow root 3\n * > focused element\n *\n * 2. focus event received by document listener\n * > document - capture listener ✅ (focus event here)\n * > shadow root 1 - capture listener ✅\n * > shadow root 2\n * > shadow root 3\n * > focused element\n *\n * 3. focus event received by root l1 listener\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅ (focus event here)\n * > shadow root 2 - capture listener ✅\n * > shadow root 3\n * > focused element\n *\n * 4. focus event received by root l2 listener\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅\n * > shadow root 2 - capture listener ✅ (focus event here)\n * > shadow root 3 - capture listener ✅\n * > focused element\n *\n * 5. focus event received by root l3 listener, no more shadow root targets\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅\n * > shadow root 2 - capture listener ✅\n * > shadow root 3 - capture listener ✅ (focus event here)\n * > focused element ✅ (no shadow root - dispatch keyborg event)\n */\n\n for (const shadowRootWeakRef of shadowTargets) {\n if (shadowRootWeakRef.deref() === shadowRoot) {\n return;\n }\n }\n\n addEventListener(shadowRoot, \"focusin\", focusInHandler);\n addEventListener(shadowRoot, \"focusout\", focusOutHandler);\n\n shadowTargets.add(new WeakRef(shadowRoot));\n\n return;\n }\n\n const details: KeyborgFocusInEventDetails = {\n relatedTarget,\n originalEvent,\n };\n\n const event: KeyborgFocusInEvent = new CustomEvent(KEYBORG_FOCUSIN, {\n cancelable: true,\n bubbles: true,\n // Allows the event to bubble past an open shadow root\n composed: true,\n detail: details,\n });\n\n // Tabster (and other users) can still use the legacy details field - keeping for backwards compat\n event.details = details;\n\n if (_canOverrideNativeFocus || data[LAST_FOCUSED_PROGRAMMATICALLY]) {\n details.isFocusedProgrammatically =\n target === data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref();\n\n data[LAST_FOCUSED_PROGRAMMATICALLY] = undefined;\n }\n\n target.dispatchEvent(event);\n };\n\n const data: KeyborgFocusEventData = [\n focusInHandler,\n focusOutHandler,\n shadowTargets,\n ];\n kwin.__keyborgData = data;\n\n addEventListener(doc, \"focusin\", focusInHandler);\n addEventListener(doc, \"focusout\", focusOutHandler);\n\n function focus(this: HTMLElement) {\n const d = (kwin as WindowWithKeyborgFocusEvent).__keyborgData;\n\n if (d) {\n d[LAST_FOCUSED_PROGRAMMATICALLY] = new WeakRef(this);\n }\n\n // eslint-disable-next-line prefer-rest-params\n return origFocus.apply(this, arguments);\n }\n\n let activeElement = doc.activeElement as Element | null;\n\n // If keyborg is created with the focus inside shadow root, we need\n // to go through the shadows up to make sure all relevant shadows\n // have focus handlers attached.\n while (activeElement && activeElement.shadowRoot) {\n onFocusIn(activeElement);\n activeElement = activeElement.shadowRoot.activeElement;\n }\n\n (focus as KeyborgFocus).__keyborgNativeFocus = origFocus;\n}\n\n/**\n * Removes keyborg event listeners and custom focus override\n * @param win The window that stores keyborg focus events\n */\nexport function disposeFocusEvent(win: Window): void {\n const kwin = win as WindowWithKeyborgFocusEvent;\n const proto = kwin.HTMLElement.prototype;\n const origFocus = (proto.focus as KeyborgFocus).__keyborgNativeFocus;\n const data = kwin.__keyborgData;\n\n if (data) {\n const doc = kwin.document;\n removeEventListener(doc, \"focusin\", data[FOCUS_IN_HANDLER]);\n removeEventListener(doc, \"focusout\", data[FOCUS_OUT_HANDLER]);\n\n for (const shadowRootWeakRef of data[SHADOW_TARGETS]) {\n const shadowRoot = shadowRootWeakRef.deref();\n\n if (shadowRoot) {\n removeEventListener(shadowRoot, \"focusin\", data[FOCUS_IN_HANDLER]);\n removeEventListener(shadowRoot, \"focusout\", data[FOCUS_OUT_HANDLER]);\n }\n }\n\n data[SHADOW_TARGETS].clear();\n\n delete kwin.__keyborgData;\n }\n\n if (origFocus) {\n proto.focus = origFocus;\n }\n}\n\n/**\n * @param win The window that stores keyborg focus events\n * @returns The last element focused with element.focus()\n */\nexport function getLastFocusedProgrammatically(\n win: Window,\n): HTMLElement | null | undefined {\n const data = (win as WindowWithKeyborgFocusEvent).__keyborgData;\n\n return data\n ? data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref() || null\n : undefined;\n}\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { addEventListener, removeEventListener } from \"./dom.mts\";\nimport {\n disposeFocusEvent,\n KeyborgFocusInEvent,\n KEYBORG_FOCUSIN,\n setupFocusEvent,\n} from \"./FocusEvent.mts\";\n\ninterface WindowWithKeyborg extends Window {\n __keyborg?: {\n core: KeyborgCoreHandle;\n refs: { [id: string]: Keyborg };\n };\n}\n\n// When a key from dismissKeys is pressed and the focus is not moved during\n// _dismissTimeout ms, keyboard navigation mode is dismissed.\nconst _dismissTimeout = 500;\n\nlet _lastId = 0;\n\nexport interface KeyborgProps {\n // Keys to be used to trigger keyboard navigation mode. By default, any key\n // will trigger it. Could be limited to, for example, just Tab (or Tab and\n // arrow keys).\n triggerKeys?: number[];\n // Keys to be used to dismiss keyboard navigation mode using keyboard (in\n // addition to mouse clicks which dismiss it). For example, Esc could be used\n // to dismiss.\n dismissKeys?: number[];\n}\n\nexport type KeyborgCallback = (isNavigatingWithKeyboard: boolean) => void;\n\n/**\n * Internal handle for the per-window core state. Not part of the public API.\n */\ninterface KeyborgCoreHandle {\n dispose(): void;\n getNavigating(): boolean;\n setNavigating(val: boolean): void;\n}\n\n/**\n * Used to determine the keyboard navigation state.\n */\nexport interface Keyborg {\n /**\n * @returns Whether the user is navigating with keyboard\n */\n isNavigatingWithKeyboard(): boolean;\n /**\n * @param callback - Called when the keyboard navigation state changes\n */\n subscribe(callback: KeyborgCallback): void;\n /**\n * @param callback - Registered with subscribe\n */\n unsubscribe(callback: KeyborgCallback): void;\n /**\n * Manually set the keyboard navigation state\n */\n setVal(isNavigatingWithKeyboard: boolean): void;\n}\n\n// Augments the public Keyborg with internal methods invoked by the core's\n// broadcast loop and by disposeKeyborg. Not exported.\ninterface KeyborgInternal extends Keyborg {\n _notify(isNavigatingWithKeyboard: boolean): void;\n _dispose(): void;\n}\n\nfunction createKeyborgCore(\n targetWindow: WindowWithKeyborg,\n props?: KeyborgProps,\n): KeyborgCoreHandle {\n let currentTargetWindow: WindowWithKeyborg | undefined = targetWindow;\n let isNavigating = false;\n let isMouseOrTouchUsedTimer: number | undefined;\n let dismissTimer: number | undefined;\n let triggerKeys: Set<number> | undefined;\n let dismissKeys: Set<number> | undefined;\n\n if (props) {\n if (props.triggerKeys?.length) {\n triggerKeys = new Set(props.triggerKeys);\n }\n if (props.dismissKeys?.length) {\n dismissKeys = new Set(props.dismissKeys);\n }\n }\n\n const broadcast = (): void => {\n const refs = currentTargetWindow?.__keyborg?.refs;\n if (refs) {\n for (const id of Object.keys(refs)) {\n (refs[id] as KeyborgInternal)._notify(isNavigating);\n }\n }\n };\n\n const setNavigating = (val: boolean): void => {\n if (isNavigating !== val) {\n isNavigating = val;\n broadcast();\n }\n };\n\n const shouldTrigger = (e: KeyboardEvent): boolean => {\n // TODO Some rich text fields can allow Tab key for indentation so it\n // doesn't need to be a navigation key. If there is a bug regarding that\n // we should revisit.\n if (e.key === \"Tab\") {\n return true;\n }\n const active = currentTargetWindow?.document\n .activeElement as HTMLElement | null;\n const isTriggerKey = !triggerKeys || triggerKeys.has(e.keyCode);\n const isEditable =\n active &&\n (active.tagName === \"INPUT\" ||\n active.tagName === \"TEXTAREA\" ||\n active.isContentEditable);\n return isTriggerKey && !isEditable;\n };\n\n const shouldDismiss = (e: KeyboardEvent): boolean => {\n return !!dismissKeys?.has(e.keyCode);\n };\n\n const scheduleDismiss = (): void => {\n const targetWindow = currentTargetWindow;\n if (!targetWindow) {\n return;\n }\n if (dismissTimer) {\n targetWindow.clearTimeout(dismissTimer);\n dismissTimer = undefined;\n }\n const previousActiveElement = targetWindow.document.activeElement;\n dismissTimer = targetWindow.setTimeout(() => {\n dismissTimer = undefined;\n const currentActiveElement = targetWindow.document.activeElement;\n if (\n previousActiveElement &&\n currentActiveElement &&\n previousActiveElement === currentActiveElement\n ) {\n // Esc was pressed, currently focused element hasn't changed.\n // Just dismiss the keyboard navigation mode.\n setNavigating(false);\n }\n }, _dismissTimeout);\n };\n\n const onFocusIn = (e: KeyborgFocusInEvent): void => {\n // When the focus is moved not programmatically and without keydown events,\n // it is likely that the focus is moved by screen reader (as it might\n // swallow the events when the screen reader shortcuts are used). The\n // screen reader usage is keyboard navigation.\n if (isMouseOrTouchUsedTimer) {\n return;\n }\n if (isNavigating) {\n return;\n }\n const details = e.detail;\n if (!details.relatedTarget) {\n return;\n }\n if (\n details.isFocusedProgrammatically ||\n details.isFocusedProgrammatically === undefined\n ) {\n return;\n }\n setNavigating(true);\n };\n\n const onMouseOrTouch = (): void => {\n if (currentTargetWindow) {\n if (isMouseOrTouchUsedTimer) {\n currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);\n }\n isMouseOrTouchUsedTimer = currentTargetWindow.setTimeout(() => {\n isMouseOrTouchUsedTimer = undefined;\n }, 1000);\n }\n setNavigating(false);\n };\n\n const onMouseDown = (e: MouseEvent): void => {\n if (\n e.buttons === 0 ||\n (e.clientX === 0 && e.clientY === 0 && e.screenX === 0 && e.screenY === 0)\n ) {\n // This is most likely an event triggered by the screen reader to\n // perform an action on an element, do not dismiss the keyboard\n // navigation mode.\n return;\n }\n onMouseOrTouch();\n };\n\n const onKeyDown = (e: KeyboardEvent): void => {\n if (isNavigating) {\n if (shouldDismiss(e)) {\n scheduleDismiss();\n }\n } else if (shouldTrigger(e)) {\n setNavigating(true);\n }\n };\n\n const targetDocument = targetWindow.document;\n addEventListener(targetDocument, KEYBORG_FOCUSIN, onFocusIn as EventListener);\n addEventListener(targetDocument, \"mousedown\", onMouseDown as EventListener);\n addEventListener(targetWindow, \"keydown\", onKeyDown as EventListener);\n addEventListener(targetDocument, \"touchstart\", onMouseOrTouch);\n addEventListener(targetDocument, \"touchend\", onMouseOrTouch);\n addEventListener(targetDocument, \"touchcancel\", onMouseOrTouch);\n\n setupFocusEvent(targetWindow);\n\n const dispose = (): void => {\n if (!currentTargetWindow) {\n return;\n }\n if (isMouseOrTouchUsedTimer) {\n currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);\n isMouseOrTouchUsedTimer = undefined;\n }\n if (dismissTimer) {\n currentTargetWindow.clearTimeout(dismissTimer);\n dismissTimer = undefined;\n }\n disposeFocusEvent(currentTargetWindow);\n const targetDocument = currentTargetWindow.document;\n removeEventListener(\n targetDocument,\n KEYBORG_FOCUSIN,\n onFocusIn as EventListener,\n );\n removeEventListener(\n targetDocument,\n \"mousedown\",\n onMouseDown as EventListener,\n );\n removeEventListener(\n currentTargetWindow,\n \"keydown\",\n onKeyDown as EventListener,\n );\n removeEventListener(targetDocument, \"touchstart\", onMouseOrTouch);\n removeEventListener(targetDocument, \"touchend\", onMouseOrTouch);\n removeEventListener(targetDocument, \"touchcancel\", onMouseOrTouch);\n currentTargetWindow = undefined;\n };\n\n return {\n dispose,\n getNavigating: () => isNavigating,\n setNavigating,\n };\n}\n\nexport function createKeyborg(win: Window, props?: KeyborgProps): Keyborg {\n const kwin = win as WindowWithKeyborg;\n const id = \"k\" + ++_lastId;\n let localWin: WindowWithKeyborg | undefined = kwin;\n let core: KeyborgCoreHandle | undefined;\n let callbacks: KeyborgCallback[] = [];\n\n const existing = kwin.__keyborg;\n if (existing) {\n core = existing.core;\n } else {\n core = createKeyborgCore(kwin, props);\n }\n\n const instance: KeyborgInternal = {\n isNavigatingWithKeyboard() {\n return !!core?.getNavigating();\n },\n subscribe(callback) {\n callbacks.push(callback);\n },\n unsubscribe(callback) {\n const index = callbacks.indexOf(callback);\n if (index >= 0) {\n callbacks.splice(index, 1);\n }\n },\n setVal(val) {\n core?.setNavigating(val);\n },\n _notify(val) {\n callbacks.forEach((cb) => cb(val));\n },\n _dispose() {\n const wkb = localWin?.__keyborg;\n if (wkb?.refs[id]) {\n delete wkb.refs[id];\n if (Object.keys(wkb.refs).length === 0) {\n wkb.core.dispose();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n delete localWin!.__keyborg;\n }\n } else if (process.env.NODE_ENV !== \"production\") {\n console.error(`Keyborg instance ${id} is being disposed incorrectly.`);\n }\n callbacks = [];\n core = undefined;\n localWin = undefined;\n },\n };\n\n if (existing) {\n existing.refs[id] = instance;\n } else {\n kwin.__keyborg = {\n core,\n refs: { [id]: instance },\n };\n }\n\n return instance;\n}\n\nexport function disposeKeyborg(instance: Keyborg): void {\n (instance as KeyborgInternal)._dispose();\n}\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport type { Keyborg, KeyborgCallback } from \"./Keyborg.mts\";\nexport { createKeyborg, disposeKeyborg } from \"./Keyborg.mts\";\n\nexport type {\n KeyborgFocusInEvent,\n KeyborgFocusInEventDetails,\n KeyborgFocusOutEvent,\n KeyborgFocusOutEventDetails,\n} from \"./FocusEvent.mts\";\nexport {\n getLastFocusedProgrammatically,\n nativeFocus,\n KEYBORG_FOCUSIN,\n KEYBORG_FOCUSOUT,\n} from \"./FocusEvent.mts\";\n\nexport const version = process.env.PKG_VERSION;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/dom.mts","../src/FocusEvent.mts","../src/Keyborg.mts","../src/index.mts"],"sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// All keyborg listeners use the capture phase; centralizing the calls lets the\n// minifier collapse the repeated DOM method names into a single short-named\n// import binding.\nexport const addEventListener = (\n target: EventTarget,\n type: string,\n handler: EventListener,\n): void => {\n target.addEventListener(type, handler, true);\n};\n\nexport const removeEventListener = (\n target: EventTarget,\n type: string,\n handler: EventListener,\n): void => {\n target.removeEventListener(type, handler, true);\n};\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { addEventListener, removeEventListener } from \"./dom.mts\";\n\nexport const KEYBORG_FOCUSIN = \"keyborg:focusin\";\nexport const KEYBORG_FOCUSOUT = \"keyborg:focusout\";\n\ninterface KeyborgFocus {\n /**\n * This is the native `focus` function that is retained so that it can be restored when keyborg is disposed\n */\n __keyborgNativeFocus?: (options?: FocusOptions | undefined) => void;\n}\n\n// Internal data stored on `window.__keyborgData` as a tuple. Nothing outside\n// this module reads these slots, so a tuple drops the property-name strings\n// from the minified output — the indexes below inline as numeric literals.\nconst FOCUS_IN_HANDLER = 0;\nconst FOCUS_OUT_HANDLER = 1;\nconst SHADOW_TARGETS = 2;\nconst LAST_FOCUSED_PROGRAMMATICALLY = 3;\ntype KeyborgFocusEventData = [\n (e: FocusEvent) => void,\n (e: FocusEvent) => void,\n Set<WeakRef<ShadowRoot>>,\n WeakRef<HTMLElement>?,\n];\n\n/**\n * Extends the global window with keyborg focus event data\n */\ninterface WindowWithKeyborgFocusEvent extends Window {\n HTMLElement: typeof HTMLElement;\n __keyborgData?: KeyborgFocusEventData;\n}\n\nfunction canOverrideNativeFocus(win: Window): boolean {\n const HTMLElement = (win as WindowWithKeyborgFocusEvent).HTMLElement;\n const origFocus = HTMLElement.prototype.focus;\n\n let isCustomFocusCalled = false;\n\n HTMLElement.prototype.focus = function focus(): void {\n isCustomFocusCalled = true;\n };\n\n const btn = win.document.createElement(\"button\");\n\n btn.focus();\n\n HTMLElement.prototype.focus = origFocus;\n\n return isCustomFocusCalled;\n}\n\nlet _canOverrideNativeFocus = false;\n\nexport interface KeyborgFocusInEventDetails {\n relatedTarget?: HTMLElement;\n isFocusedProgrammatically?: boolean;\n originalEvent?: FocusEvent;\n}\n\nexport interface KeyborgFocusInEvent extends CustomEvent<KeyborgFocusInEventDetails> {\n /**\n * @deprecated - used `event.detail`\n */\n details?: KeyborgFocusInEventDetails;\n}\n\nexport interface KeyborgFocusOutEventDetails {\n originalEvent: FocusEvent;\n}\n\nexport type KeyborgFocusOutEvent = CustomEvent<KeyborgFocusOutEventDetails>;\n\n/**\n * Guarantees that the native `focus` will be used\n */\nexport function nativeFocus(element: HTMLElement): void {\n const focus = element.focus as KeyborgFocus;\n\n if (focus.__keyborgNativeFocus) {\n focus.__keyborgNativeFocus.call(element);\n } else {\n element.focus();\n }\n}\n\n/**\n * Overrides the native `focus` and setups the keyborg focus event\n */\nexport function setupFocusEvent(win: Window): void {\n const kwin = win as WindowWithKeyborgFocusEvent;\n const doc = kwin.document;\n const proto = kwin.HTMLElement.prototype;\n\n if (!_canOverrideNativeFocus) {\n _canOverrideNativeFocus = canOverrideNativeFocus(kwin);\n }\n\n const origFocus = proto.focus;\n\n if ((origFocus as KeyborgFocus).__keyborgNativeFocus) {\n // Already set up.\n return;\n }\n\n proto.focus = focus;\n\n const shadowTargets: Set<WeakRef<ShadowRoot>> = new Set();\n\n const focusOutHandler = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n\n if (!target) {\n return;\n }\n\n const event: KeyborgFocusOutEvent = new CustomEvent(KEYBORG_FOCUSOUT, {\n cancelable: true,\n bubbles: true,\n // Allows the event to bubble past an open shadow root\n composed: true,\n detail: {\n originalEvent: e,\n },\n });\n\n target.dispatchEvent(event);\n };\n\n const focusInHandler = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n\n if (!target) {\n return;\n }\n\n let node: Node | null | undefined = e.composedPath()[0] as\n | Node\n | null\n | undefined;\n\n const currentShadows: Set<ShadowRoot> = new Set();\n\n while (node) {\n if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\n currentShadows.add(node as ShadowRoot);\n node = (node as ShadowRoot).host;\n } else {\n node = node.parentNode;\n }\n }\n\n for (const shadowRootWeakRef of shadowTargets) {\n const shadowRoot = shadowRootWeakRef.deref();\n\n if (!shadowRoot || !currentShadows.has(shadowRoot)) {\n shadowTargets.delete(shadowRootWeakRef);\n\n if (shadowRoot) {\n removeEventListener(shadowRoot, \"focusin\", focusInHandler);\n removeEventListener(shadowRoot, \"focusout\", focusOutHandler);\n }\n }\n }\n\n onFocusIn(target, (e.relatedTarget as HTMLElement | null) || undefined);\n };\n\n const onFocusIn = (\n target: Element,\n relatedTarget?: HTMLElement,\n originalEvent?: FocusEvent,\n ) => {\n const shadowRoot = target.shadowRoot;\n\n if (shadowRoot) {\n /**\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1512028\n * focusin events don't bubble up through an open shadow root once focus is inside\n * once focus moves into a shadow root - we drop the same focusin handler there\n * keyborg's custom event will still bubble up since it is composed\n * event handlers should be cleaned up once focus leaves the shadow root.\n *\n * When a focusin event is dispatched from a shadow root, its target is the shadow root parent.\n * Each shadow root encounter requires a new capture listener.\n * Why capture? - we want to follow the focus event in order or descending nested shadow roots\n * When there are no more shadow root targets - dispatch the keyborg:focusin event\n *\n * 1. no focus event\n * > document - capture listener ✅\n * > shadow root 1\n * > shadow root 2\n * > shadow root 3\n * > focused element\n *\n * 2. focus event received by document listener\n * > document - capture listener ✅ (focus event here)\n * > shadow root 1 - capture listener ✅\n * > shadow root 2\n * > shadow root 3\n * > focused element\n *\n * 3. focus event received by root l1 listener\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅ (focus event here)\n * > shadow root 2 - capture listener ✅\n * > shadow root 3\n * > focused element\n *\n * 4. focus event received by root l2 listener\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅\n * > shadow root 2 - capture listener ✅ (focus event here)\n * > shadow root 3 - capture listener ✅\n * > focused element\n *\n * 5. focus event received by root l3 listener, no more shadow root targets\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅\n * > shadow root 2 - capture listener ✅\n * > shadow root 3 - capture listener ✅ (focus event here)\n * > focused element ✅ (no shadow root - dispatch keyborg event)\n */\n\n for (const shadowRootWeakRef of shadowTargets) {\n if (shadowRootWeakRef.deref() === shadowRoot) {\n return;\n }\n }\n\n addEventListener(shadowRoot, \"focusin\", focusInHandler);\n addEventListener(shadowRoot, \"focusout\", focusOutHandler);\n\n shadowTargets.add(new WeakRef(shadowRoot));\n\n return;\n }\n\n const details: KeyborgFocusInEventDetails = {\n relatedTarget,\n originalEvent,\n };\n\n const event: KeyborgFocusInEvent = new CustomEvent(KEYBORG_FOCUSIN, {\n cancelable: true,\n bubbles: true,\n // Allows the event to bubble past an open shadow root\n composed: true,\n detail: details,\n });\n\n // Tabster (and other users) can still use the legacy details field - keeping for backwards compat\n event.details = details;\n\n if (_canOverrideNativeFocus || data[LAST_FOCUSED_PROGRAMMATICALLY]) {\n details.isFocusedProgrammatically =\n target === data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref();\n\n data[LAST_FOCUSED_PROGRAMMATICALLY] = undefined;\n }\n\n target.dispatchEvent(event);\n };\n\n const data: KeyborgFocusEventData = [\n focusInHandler,\n focusOutHandler,\n shadowTargets,\n ];\n kwin.__keyborgData = data;\n\n addEventListener(doc, \"focusin\", focusInHandler);\n addEventListener(doc, \"focusout\", focusOutHandler);\n\n function focus(this: HTMLElement) {\n const d = (kwin as WindowWithKeyborgFocusEvent).__keyborgData;\n\n if (d) {\n d[LAST_FOCUSED_PROGRAMMATICALLY] = new WeakRef(this);\n }\n\n // eslint-disable-next-line prefer-rest-params\n return origFocus.apply(this, arguments);\n }\n\n let activeElement = doc.activeElement as Element | null;\n\n // If keyborg is created with the focus inside shadow root, we need\n // to go through the shadows up to make sure all relevant shadows\n // have focus handlers attached.\n while (activeElement && activeElement.shadowRoot) {\n onFocusIn(activeElement);\n activeElement = activeElement.shadowRoot.activeElement;\n }\n\n (focus as KeyborgFocus).__keyborgNativeFocus = origFocus;\n}\n\n/**\n * Removes keyborg event listeners and custom focus override\n * @param win The window that stores keyborg focus events\n */\nexport function disposeFocusEvent(win: Window): void {\n const kwin = win as WindowWithKeyborgFocusEvent;\n const proto = kwin.HTMLElement.prototype;\n const origFocus = (proto.focus as KeyborgFocus).__keyborgNativeFocus;\n const data = kwin.__keyborgData;\n\n if (data) {\n const doc = kwin.document;\n removeEventListener(doc, \"focusin\", data[FOCUS_IN_HANDLER]);\n removeEventListener(doc, \"focusout\", data[FOCUS_OUT_HANDLER]);\n\n for (const shadowRootWeakRef of data[SHADOW_TARGETS]) {\n const shadowRoot = shadowRootWeakRef.deref();\n\n if (shadowRoot) {\n removeEventListener(shadowRoot, \"focusin\", data[FOCUS_IN_HANDLER]);\n removeEventListener(shadowRoot, \"focusout\", data[FOCUS_OUT_HANDLER]);\n }\n }\n\n data[SHADOW_TARGETS].clear();\n\n delete kwin.__keyborgData;\n }\n\n if (origFocus) {\n proto.focus = origFocus;\n }\n}\n\n/**\n * @param win The window that stores keyborg focus events\n * @returns The last element focused with element.focus()\n */\nexport function getLastFocusedProgrammatically(\n win: Window,\n): HTMLElement | null | undefined {\n const data = (win as WindowWithKeyborgFocusEvent).__keyborgData;\n\n return data\n ? data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref() || null\n : undefined;\n}\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { addEventListener, removeEventListener } from \"./dom.mts\";\nimport {\n disposeFocusEvent,\n KeyborgFocusInEvent,\n KEYBORG_FOCUSIN,\n setupFocusEvent,\n} from \"./FocusEvent.mts\";\n\ninterface WindowWithKeyborg extends Window {\n __keyborg?: {\n core: KeyborgCoreHandle;\n refs: { [id: string]: Keyborg };\n };\n}\n\n// When a key from dismissKeys is pressed and the focus is not moved during\n// _dismissTimeout ms, keyboard navigation mode is dismissed.\nconst _dismissTimeout = 500;\n\nlet _lastId = 0;\n\nexport interface KeyborgProps {\n // Keys to be used to trigger keyboard navigation mode. By default, any key\n // will trigger it. Could be limited to, for example, just Tab (or Tab and\n // arrow keys).\n triggerKeys?: number[];\n // Keys to be used to dismiss keyboard navigation mode using keyboard (in\n // addition to mouse clicks which dismiss it). For example, Esc could be used\n // to dismiss.\n dismissKeys?: number[];\n}\n\nexport type KeyborgCallback = (isNavigatingWithKeyboard: boolean) => void;\n\n/**\n * Internal handle for the per-window core state. Not part of the public API.\n *\n * Shape is part of the `__keyborg.core` slot contract: when multiple keyborg\n * majors share the same window, the second loader reads `core` set by the\n * first. Keep `isNavigatingWithKeyboard` as a writable property accessor and\n * `dispose()` as a method so older majors can still read/write state without\n * TypeError. Changes here are breaking for that interop.\n */\ninterface KeyborgCoreHandle {\n isNavigatingWithKeyboard: boolean;\n dispose(): void;\n}\n\n/**\n * Used to determine the keyboard navigation state.\n */\nexport interface Keyborg {\n /**\n * @returns Whether the user is navigating with keyboard\n */\n isNavigatingWithKeyboard(): boolean;\n /**\n * @param callback - Called when the keyboard navigation state changes\n */\n subscribe(callback: KeyborgCallback): void;\n /**\n * @param callback - Registered with subscribe\n */\n unsubscribe(callback: KeyborgCallback): void;\n /**\n * Manually set the keyboard navigation state\n */\n setVal(isNavigatingWithKeyboard: boolean): void;\n}\n\n// Augments the public Keyborg with internal members that also form the\n// `__keyborg.refs` slot wire protocol. The shape — `_cb` callback array and\n// `dispose()` method — matches keyborg <= 2.6.0's `Keyborg` class so that\n// mixed-version environments can broadcast and tear down each other's\n// instances without TypeError. Changes here are breaking for that interop.\ninterface KeyborgInternal extends Keyborg {\n _cb: KeyborgCallback[];\n dispose(): void;\n}\n\nfunction createKeyborgCore(\n targetWindow: WindowWithKeyborg,\n props?: KeyborgProps,\n): KeyborgCoreHandle {\n let currentTargetWindow: WindowWithKeyborg | undefined = targetWindow;\n let isNavigating = false;\n let isMouseOrTouchUsedTimer: number | undefined;\n let dismissTimer: number | undefined;\n let triggerKeys: Set<number> | undefined;\n let dismissKeys: Set<number> | undefined;\n\n if (props) {\n if (props.triggerKeys?.length) {\n triggerKeys = new Set(props.triggerKeys);\n }\n if (props.dismissKeys?.length) {\n dismissKeys = new Set(props.dismissKeys);\n }\n }\n\n const broadcast = (): void => {\n const refs = currentTargetWindow?.__keyborg?.refs;\n if (refs) {\n for (const id of Object.keys(refs)) {\n (refs[id] as KeyborgInternal)._cb.forEach((cb) => cb(isNavigating));\n }\n }\n };\n\n const setNavigating = (val: boolean): void => {\n if (isNavigating !== val) {\n isNavigating = val;\n broadcast();\n }\n };\n\n const shouldTrigger = (e: KeyboardEvent): boolean => {\n // TODO Some rich text fields can allow Tab key for indentation so it\n // doesn't need to be a navigation key. If there is a bug regarding that\n // we should revisit.\n if (e.key === \"Tab\") {\n return true;\n }\n const active = currentTargetWindow?.document\n .activeElement as HTMLElement | null;\n const isTriggerKey = !triggerKeys || triggerKeys.has(e.keyCode);\n const isEditable =\n active &&\n (active.tagName === \"INPUT\" ||\n active.tagName === \"TEXTAREA\" ||\n active.isContentEditable);\n return isTriggerKey && !isEditable;\n };\n\n const shouldDismiss = (e: KeyboardEvent): boolean => {\n return !!dismissKeys?.has(e.keyCode);\n };\n\n const scheduleDismiss = (): void => {\n const targetWindow = currentTargetWindow;\n if (!targetWindow) {\n return;\n }\n if (dismissTimer) {\n targetWindow.clearTimeout(dismissTimer);\n dismissTimer = undefined;\n }\n const previousActiveElement = targetWindow.document.activeElement;\n dismissTimer = targetWindow.setTimeout(() => {\n dismissTimer = undefined;\n const currentActiveElement = targetWindow.document.activeElement;\n if (\n previousActiveElement &&\n currentActiveElement &&\n previousActiveElement === currentActiveElement\n ) {\n // Esc was pressed, currently focused element hasn't changed.\n // Just dismiss the keyboard navigation mode.\n setNavigating(false);\n }\n }, _dismissTimeout);\n };\n\n const onFocusIn = (e: KeyborgFocusInEvent): void => {\n // When the focus is moved not programmatically and without keydown events,\n // it is likely that the focus is moved by screen reader (as it might\n // swallow the events when the screen reader shortcuts are used). The\n // screen reader usage is keyboard navigation.\n if (isMouseOrTouchUsedTimer) {\n return;\n }\n if (isNavigating) {\n return;\n }\n const details = e.detail;\n if (!details.relatedTarget) {\n return;\n }\n if (\n details.isFocusedProgrammatically ||\n details.isFocusedProgrammatically === undefined\n ) {\n return;\n }\n setNavigating(true);\n };\n\n const onMouseOrTouch = (): void => {\n if (currentTargetWindow) {\n if (isMouseOrTouchUsedTimer) {\n currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);\n }\n isMouseOrTouchUsedTimer = currentTargetWindow.setTimeout(() => {\n isMouseOrTouchUsedTimer = undefined;\n }, 1000);\n }\n setNavigating(false);\n };\n\n const onMouseDown = (e: MouseEvent): void => {\n if (\n e.buttons === 0 ||\n (e.clientX === 0 && e.clientY === 0 && e.screenX === 0 && e.screenY === 0)\n ) {\n // This is most likely an event triggered by the screen reader to\n // perform an action on an element, do not dismiss the keyboard\n // navigation mode.\n return;\n }\n onMouseOrTouch();\n };\n\n const onKeyDown = (e: KeyboardEvent): void => {\n if (isNavigating) {\n if (shouldDismiss(e)) {\n scheduleDismiss();\n }\n } else if (shouldTrigger(e)) {\n setNavigating(true);\n }\n };\n\n const targetDocument = targetWindow.document;\n addEventListener(targetDocument, KEYBORG_FOCUSIN, onFocusIn as EventListener);\n addEventListener(targetDocument, \"mousedown\", onMouseDown as EventListener);\n addEventListener(targetWindow, \"keydown\", onKeyDown as EventListener);\n addEventListener(targetDocument, \"touchstart\", onMouseOrTouch);\n addEventListener(targetDocument, \"touchend\", onMouseOrTouch);\n addEventListener(targetDocument, \"touchcancel\", onMouseOrTouch);\n\n setupFocusEvent(targetWindow);\n\n const dispose = (): void => {\n if (!currentTargetWindow) {\n return;\n }\n if (isMouseOrTouchUsedTimer) {\n currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);\n isMouseOrTouchUsedTimer = undefined;\n }\n if (dismissTimer) {\n currentTargetWindow.clearTimeout(dismissTimer);\n dismissTimer = undefined;\n }\n disposeFocusEvent(currentTargetWindow);\n const targetDocument = currentTargetWindow.document;\n removeEventListener(\n targetDocument,\n KEYBORG_FOCUSIN,\n onFocusIn as EventListener,\n );\n removeEventListener(\n targetDocument,\n \"mousedown\",\n onMouseDown as EventListener,\n );\n removeEventListener(\n currentTargetWindow,\n \"keydown\",\n onKeyDown as EventListener,\n );\n removeEventListener(targetDocument, \"touchstart\", onMouseOrTouch);\n removeEventListener(targetDocument, \"touchend\", onMouseOrTouch);\n removeEventListener(targetDocument, \"touchcancel\", onMouseOrTouch);\n currentTargetWindow = undefined;\n };\n\n return {\n dispose,\n get isNavigatingWithKeyboard() {\n return isNavigating;\n },\n set isNavigatingWithKeyboard(val: boolean) {\n setNavigating(val);\n },\n };\n}\n\nexport function createKeyborg(win: Window, props?: KeyborgProps): Keyborg {\n const kwin = win as WindowWithKeyborg;\n const id = \"k\" + ++_lastId;\n let localWin: WindowWithKeyborg | undefined = kwin;\n let core: KeyborgCoreHandle | undefined;\n // `callbacks` is exposed as `instance._cb` to satisfy the slot wire\n // protocol. We mutate the array in place (push/splice/length=0) so the\n // reference stays stable for foreign-version broadcasts.\n const callbacks: KeyborgCallback[] = [];\n\n const existing = kwin.__keyborg;\n if (existing) {\n core = existing.core;\n } else {\n core = createKeyborgCore(kwin, props);\n }\n\n const instance: KeyborgInternal = {\n isNavigatingWithKeyboard() {\n return !!core?.isNavigatingWithKeyboard;\n },\n subscribe(callback) {\n callbacks.push(callback);\n },\n unsubscribe(callback) {\n const index = callbacks.indexOf(callback);\n if (index >= 0) {\n callbacks.splice(index, 1);\n }\n },\n setVal(val) {\n if (core) {\n core.isNavigatingWithKeyboard = val;\n }\n },\n _cb: callbacks,\n dispose() {\n const wkb = localWin?.__keyborg;\n if (wkb?.refs[id]) {\n delete wkb.refs[id];\n if (Object.keys(wkb.refs).length === 0) {\n wkb.core.dispose();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n delete localWin!.__keyborg;\n }\n } else if (process.env.NODE_ENV !== \"production\") {\n console.error(`Keyborg instance ${id} is being disposed incorrectly.`);\n }\n callbacks.length = 0;\n core = undefined;\n localWin = undefined;\n },\n };\n\n if (existing) {\n existing.refs[id] = instance;\n } else {\n kwin.__keyborg = {\n core,\n refs: { [id]: instance },\n };\n }\n\n return instance;\n}\n\nexport function disposeKeyborg(instance: Keyborg): void {\n (instance as KeyborgInternal).dispose();\n}\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport type { Keyborg, KeyborgCallback } from \"./Keyborg.mts\";\nexport { createKeyborg, disposeKeyborg } from \"./Keyborg.mts\";\n\nexport type {\n KeyborgFocusInEvent,\n KeyborgFocusInEventDetails,\n KeyborgFocusOutEvent,\n KeyborgFocusOutEventDetails,\n} from \"./FocusEvent.mts\";\nexport {\n getLastFocusedProgrammatically,\n nativeFocus,\n KEYBORG_FOCUSIN,\n KEYBORG_FOCUSOUT,\n} from \"./FocusEvent.mts\";\n\nexport const version = process.env.PKG_VERSION;\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -234,7 +234,7 @@ function createKeyborgCore(targetWindow, props) {
|
|
|
234
234
|
}
|
|
235
235
|
const broadcast = () => {
|
|
236
236
|
const refs = currentTargetWindow?.__keyborg?.refs;
|
|
237
|
-
if (refs) for (const id of Object.keys(refs)) refs[id].
|
|
237
|
+
if (refs) for (const id of Object.keys(refs)) refs[id]._cb.forEach((cb) => cb(isNavigating));
|
|
238
238
|
};
|
|
239
239
|
const setNavigating = (val) => {
|
|
240
240
|
if (isNavigating !== val) {
|
|
@@ -322,8 +322,12 @@ function createKeyborgCore(targetWindow, props) {
|
|
|
322
322
|
};
|
|
323
323
|
return {
|
|
324
324
|
dispose,
|
|
325
|
-
|
|
326
|
-
|
|
325
|
+
get isNavigatingWithKeyboard() {
|
|
326
|
+
return isNavigating;
|
|
327
|
+
},
|
|
328
|
+
set isNavigatingWithKeyboard(val) {
|
|
329
|
+
setNavigating(val);
|
|
330
|
+
}
|
|
327
331
|
};
|
|
328
332
|
}
|
|
329
333
|
function createKeyborg(win, props) {
|
|
@@ -331,13 +335,13 @@ function createKeyborg(win, props) {
|
|
|
331
335
|
const id = "k" + ++_lastId;
|
|
332
336
|
let localWin = kwin;
|
|
333
337
|
let core;
|
|
334
|
-
|
|
338
|
+
const callbacks = [];
|
|
335
339
|
const existing = kwin.__keyborg;
|
|
336
340
|
if (existing) core = existing.core;
|
|
337
341
|
else core = createKeyborgCore(kwin, props);
|
|
338
342
|
const instance = {
|
|
339
343
|
isNavigatingWithKeyboard() {
|
|
340
|
-
return !!core?.
|
|
344
|
+
return !!core?.isNavigatingWithKeyboard;
|
|
341
345
|
},
|
|
342
346
|
subscribe(callback) {
|
|
343
347
|
callbacks.push(callback);
|
|
@@ -347,12 +351,10 @@ function createKeyborg(win, props) {
|
|
|
347
351
|
if (index >= 0) callbacks.splice(index, 1);
|
|
348
352
|
},
|
|
349
353
|
setVal(val) {
|
|
350
|
-
core
|
|
351
|
-
},
|
|
352
|
-
_notify(val) {
|
|
353
|
-
callbacks.forEach((cb) => cb(val));
|
|
354
|
+
if (core) core.isNavigatingWithKeyboard = val;
|
|
354
355
|
},
|
|
355
|
-
|
|
356
|
+
_cb: callbacks,
|
|
357
|
+
dispose() {
|
|
356
358
|
const wkb = localWin?.__keyborg;
|
|
357
359
|
if (wkb?.refs[id]) {
|
|
358
360
|
delete wkb.refs[id];
|
|
@@ -361,7 +363,7 @@ function createKeyborg(win, props) {
|
|
|
361
363
|
delete localWin.__keyborg;
|
|
362
364
|
}
|
|
363
365
|
} else if (process.env.NODE_ENV !== "production") console.error(`Keyborg instance ${id} is being disposed incorrectly.`);
|
|
364
|
-
callbacks =
|
|
366
|
+
callbacks.length = 0;
|
|
365
367
|
core = void 0;
|
|
366
368
|
localWin = void 0;
|
|
367
369
|
}
|
|
@@ -374,12 +376,12 @@ function createKeyborg(win, props) {
|
|
|
374
376
|
return instance;
|
|
375
377
|
}
|
|
376
378
|
function disposeKeyborg(instance) {
|
|
377
|
-
instance.
|
|
379
|
+
instance.dispose();
|
|
378
380
|
}
|
|
379
381
|
|
|
380
382
|
//#endregion
|
|
381
383
|
//#region src/index.mts
|
|
382
|
-
const version = "2.14.
|
|
384
|
+
const version = "2.14.1";
|
|
383
385
|
|
|
384
386
|
//#endregion
|
|
385
387
|
export { KEYBORG_FOCUSIN, KEYBORG_FOCUSOUT, createKeyborg, disposeKeyborg, getLastFocusedProgrammatically, nativeFocus, version };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/dom.mts","../src/FocusEvent.mts","../src/Keyborg.mts","../src/index.mts"],"sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// All keyborg listeners use the capture phase; centralizing the calls lets the\n// minifier collapse the repeated DOM method names into a single short-named\n// import binding.\nexport const addEventListener = (\n target: EventTarget,\n type: string,\n handler: EventListener,\n): void => {\n target.addEventListener(type, handler, true);\n};\n\nexport const removeEventListener = (\n target: EventTarget,\n type: string,\n handler: EventListener,\n): void => {\n target.removeEventListener(type, handler, true);\n};\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { addEventListener, removeEventListener } from \"./dom.mts\";\n\nexport const KEYBORG_FOCUSIN = \"keyborg:focusin\";\nexport const KEYBORG_FOCUSOUT = \"keyborg:focusout\";\n\ninterface KeyborgFocus {\n /**\n * This is the native `focus` function that is retained so that it can be restored when keyborg is disposed\n */\n __keyborgNativeFocus?: (options?: FocusOptions | undefined) => void;\n}\n\n// Internal data stored on `window.__keyborgData` as a tuple. Nothing outside\n// this module reads these slots, so a tuple drops the property-name strings\n// from the minified output — the indexes below inline as numeric literals.\nconst FOCUS_IN_HANDLER = 0;\nconst FOCUS_OUT_HANDLER = 1;\nconst SHADOW_TARGETS = 2;\nconst LAST_FOCUSED_PROGRAMMATICALLY = 3;\ntype KeyborgFocusEventData = [\n (e: FocusEvent) => void,\n (e: FocusEvent) => void,\n Set<WeakRef<ShadowRoot>>,\n WeakRef<HTMLElement>?,\n];\n\n/**\n * Extends the global window with keyborg focus event data\n */\ninterface WindowWithKeyborgFocusEvent extends Window {\n HTMLElement: typeof HTMLElement;\n __keyborgData?: KeyborgFocusEventData;\n}\n\nfunction canOverrideNativeFocus(win: Window): boolean {\n const HTMLElement = (win as WindowWithKeyborgFocusEvent).HTMLElement;\n const origFocus = HTMLElement.prototype.focus;\n\n let isCustomFocusCalled = false;\n\n HTMLElement.prototype.focus = function focus(): void {\n isCustomFocusCalled = true;\n };\n\n const btn = win.document.createElement(\"button\");\n\n btn.focus();\n\n HTMLElement.prototype.focus = origFocus;\n\n return isCustomFocusCalled;\n}\n\nlet _canOverrideNativeFocus = false;\n\nexport interface KeyborgFocusInEventDetails {\n relatedTarget?: HTMLElement;\n isFocusedProgrammatically?: boolean;\n originalEvent?: FocusEvent;\n}\n\nexport interface KeyborgFocusInEvent extends CustomEvent<KeyborgFocusInEventDetails> {\n /**\n * @deprecated - used `event.detail`\n */\n details?: KeyborgFocusInEventDetails;\n}\n\nexport interface KeyborgFocusOutEventDetails {\n originalEvent: FocusEvent;\n}\n\nexport type KeyborgFocusOutEvent = CustomEvent<KeyborgFocusOutEventDetails>;\n\n/**\n * Guarantees that the native `focus` will be used\n */\nexport function nativeFocus(element: HTMLElement): void {\n const focus = element.focus as KeyborgFocus;\n\n if (focus.__keyborgNativeFocus) {\n focus.__keyborgNativeFocus.call(element);\n } else {\n element.focus();\n }\n}\n\n/**\n * Overrides the native `focus` and setups the keyborg focus event\n */\nexport function setupFocusEvent(win: Window): void {\n const kwin = win as WindowWithKeyborgFocusEvent;\n const doc = kwin.document;\n const proto = kwin.HTMLElement.prototype;\n\n if (!_canOverrideNativeFocus) {\n _canOverrideNativeFocus = canOverrideNativeFocus(kwin);\n }\n\n const origFocus = proto.focus;\n\n if ((origFocus as KeyborgFocus).__keyborgNativeFocus) {\n // Already set up.\n return;\n }\n\n proto.focus = focus;\n\n const shadowTargets: Set<WeakRef<ShadowRoot>> = new Set();\n\n const focusOutHandler = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n\n if (!target) {\n return;\n }\n\n const event: KeyborgFocusOutEvent = new CustomEvent(KEYBORG_FOCUSOUT, {\n cancelable: true,\n bubbles: true,\n // Allows the event to bubble past an open shadow root\n composed: true,\n detail: {\n originalEvent: e,\n },\n });\n\n target.dispatchEvent(event);\n };\n\n const focusInHandler = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n\n if (!target) {\n return;\n }\n\n let node: Node | null | undefined = e.composedPath()[0] as\n | Node\n | null\n | undefined;\n\n const currentShadows: Set<ShadowRoot> = new Set();\n\n while (node) {\n if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\n currentShadows.add(node as ShadowRoot);\n node = (node as ShadowRoot).host;\n } else {\n node = node.parentNode;\n }\n }\n\n for (const shadowRootWeakRef of shadowTargets) {\n const shadowRoot = shadowRootWeakRef.deref();\n\n if (!shadowRoot || !currentShadows.has(shadowRoot)) {\n shadowTargets.delete(shadowRootWeakRef);\n\n if (shadowRoot) {\n removeEventListener(shadowRoot, \"focusin\", focusInHandler);\n removeEventListener(shadowRoot, \"focusout\", focusOutHandler);\n }\n }\n }\n\n onFocusIn(target, (e.relatedTarget as HTMLElement | null) || undefined);\n };\n\n const onFocusIn = (\n target: Element,\n relatedTarget?: HTMLElement,\n originalEvent?: FocusEvent,\n ) => {\n const shadowRoot = target.shadowRoot;\n\n if (shadowRoot) {\n /**\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1512028\n * focusin events don't bubble up through an open shadow root once focus is inside\n * once focus moves into a shadow root - we drop the same focusin handler there\n * keyborg's custom event will still bubble up since it is composed\n * event handlers should be cleaned up once focus leaves the shadow root.\n *\n * When a focusin event is dispatched from a shadow root, its target is the shadow root parent.\n * Each shadow root encounter requires a new capture listener.\n * Why capture? - we want to follow the focus event in order or descending nested shadow roots\n * When there are no more shadow root targets - dispatch the keyborg:focusin event\n *\n * 1. no focus event\n * > document - capture listener ✅\n * > shadow root 1\n * > shadow root 2\n * > shadow root 3\n * > focused element\n *\n * 2. focus event received by document listener\n * > document - capture listener ✅ (focus event here)\n * > shadow root 1 - capture listener ✅\n * > shadow root 2\n * > shadow root 3\n * > focused element\n *\n * 3. focus event received by root l1 listener\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅ (focus event here)\n * > shadow root 2 - capture listener ✅\n * > shadow root 3\n * > focused element\n *\n * 4. focus event received by root l2 listener\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅\n * > shadow root 2 - capture listener ✅ (focus event here)\n * > shadow root 3 - capture listener ✅\n * > focused element\n *\n * 5. focus event received by root l3 listener, no more shadow root targets\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅\n * > shadow root 2 - capture listener ✅\n * > shadow root 3 - capture listener ✅ (focus event here)\n * > focused element ✅ (no shadow root - dispatch keyborg event)\n */\n\n for (const shadowRootWeakRef of shadowTargets) {\n if (shadowRootWeakRef.deref() === shadowRoot) {\n return;\n }\n }\n\n addEventListener(shadowRoot, \"focusin\", focusInHandler);\n addEventListener(shadowRoot, \"focusout\", focusOutHandler);\n\n shadowTargets.add(new WeakRef(shadowRoot));\n\n return;\n }\n\n const details: KeyborgFocusInEventDetails = {\n relatedTarget,\n originalEvent,\n };\n\n const event: KeyborgFocusInEvent = new CustomEvent(KEYBORG_FOCUSIN, {\n cancelable: true,\n bubbles: true,\n // Allows the event to bubble past an open shadow root\n composed: true,\n detail: details,\n });\n\n // Tabster (and other users) can still use the legacy details field - keeping for backwards compat\n event.details = details;\n\n if (_canOverrideNativeFocus || data[LAST_FOCUSED_PROGRAMMATICALLY]) {\n details.isFocusedProgrammatically =\n target === data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref();\n\n data[LAST_FOCUSED_PROGRAMMATICALLY] = undefined;\n }\n\n target.dispatchEvent(event);\n };\n\n const data: KeyborgFocusEventData = [\n focusInHandler,\n focusOutHandler,\n shadowTargets,\n ];\n kwin.__keyborgData = data;\n\n addEventListener(doc, \"focusin\", focusInHandler);\n addEventListener(doc, \"focusout\", focusOutHandler);\n\n function focus(this: HTMLElement) {\n const d = (kwin as WindowWithKeyborgFocusEvent).__keyborgData;\n\n if (d) {\n d[LAST_FOCUSED_PROGRAMMATICALLY] = new WeakRef(this);\n }\n\n // eslint-disable-next-line prefer-rest-params\n return origFocus.apply(this, arguments);\n }\n\n let activeElement = doc.activeElement as Element | null;\n\n // If keyborg is created with the focus inside shadow root, we need\n // to go through the shadows up to make sure all relevant shadows\n // have focus handlers attached.\n while (activeElement && activeElement.shadowRoot) {\n onFocusIn(activeElement);\n activeElement = activeElement.shadowRoot.activeElement;\n }\n\n (focus as KeyborgFocus).__keyborgNativeFocus = origFocus;\n}\n\n/**\n * Removes keyborg event listeners and custom focus override\n * @param win The window that stores keyborg focus events\n */\nexport function disposeFocusEvent(win: Window): void {\n const kwin = win as WindowWithKeyborgFocusEvent;\n const proto = kwin.HTMLElement.prototype;\n const origFocus = (proto.focus as KeyborgFocus).__keyborgNativeFocus;\n const data = kwin.__keyborgData;\n\n if (data) {\n const doc = kwin.document;\n removeEventListener(doc, \"focusin\", data[FOCUS_IN_HANDLER]);\n removeEventListener(doc, \"focusout\", data[FOCUS_OUT_HANDLER]);\n\n for (const shadowRootWeakRef of data[SHADOW_TARGETS]) {\n const shadowRoot = shadowRootWeakRef.deref();\n\n if (shadowRoot) {\n removeEventListener(shadowRoot, \"focusin\", data[FOCUS_IN_HANDLER]);\n removeEventListener(shadowRoot, \"focusout\", data[FOCUS_OUT_HANDLER]);\n }\n }\n\n data[SHADOW_TARGETS].clear();\n\n delete kwin.__keyborgData;\n }\n\n if (origFocus) {\n proto.focus = origFocus;\n }\n}\n\n/**\n * @param win The window that stores keyborg focus events\n * @returns The last element focused with element.focus()\n */\nexport function getLastFocusedProgrammatically(\n win: Window,\n): HTMLElement | null | undefined {\n const data = (win as WindowWithKeyborgFocusEvent).__keyborgData;\n\n return data\n ? data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref() || null\n : undefined;\n}\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { addEventListener, removeEventListener } from \"./dom.mts\";\nimport {\n disposeFocusEvent,\n KeyborgFocusInEvent,\n KEYBORG_FOCUSIN,\n setupFocusEvent,\n} from \"./FocusEvent.mts\";\n\ninterface WindowWithKeyborg extends Window {\n __keyborg?: {\n core: KeyborgCoreHandle;\n refs: { [id: string]: Keyborg };\n };\n}\n\n// When a key from dismissKeys is pressed and the focus is not moved during\n// _dismissTimeout ms, keyboard navigation mode is dismissed.\nconst _dismissTimeout = 500;\n\nlet _lastId = 0;\n\nexport interface KeyborgProps {\n // Keys to be used to trigger keyboard navigation mode. By default, any key\n // will trigger it. Could be limited to, for example, just Tab (or Tab and\n // arrow keys).\n triggerKeys?: number[];\n // Keys to be used to dismiss keyboard navigation mode using keyboard (in\n // addition to mouse clicks which dismiss it). For example, Esc could be used\n // to dismiss.\n dismissKeys?: number[];\n}\n\nexport type KeyborgCallback = (isNavigatingWithKeyboard: boolean) => void;\n\n/**\n * Internal handle for the per-window core state. Not part of the public API.\n */\ninterface KeyborgCoreHandle {\n dispose(): void;\n getNavigating(): boolean;\n setNavigating(val: boolean): void;\n}\n\n/**\n * Used to determine the keyboard navigation state.\n */\nexport interface Keyborg {\n /**\n * @returns Whether the user is navigating with keyboard\n */\n isNavigatingWithKeyboard(): boolean;\n /**\n * @param callback - Called when the keyboard navigation state changes\n */\n subscribe(callback: KeyborgCallback): void;\n /**\n * @param callback - Registered with subscribe\n */\n unsubscribe(callback: KeyborgCallback): void;\n /**\n * Manually set the keyboard navigation state\n */\n setVal(isNavigatingWithKeyboard: boolean): void;\n}\n\n// Augments the public Keyborg with internal methods invoked by the core's\n// broadcast loop and by disposeKeyborg. Not exported.\ninterface KeyborgInternal extends Keyborg {\n _notify(isNavigatingWithKeyboard: boolean): void;\n _dispose(): void;\n}\n\nfunction createKeyborgCore(\n targetWindow: WindowWithKeyborg,\n props?: KeyborgProps,\n): KeyborgCoreHandle {\n let currentTargetWindow: WindowWithKeyborg | undefined = targetWindow;\n let isNavigating = false;\n let isMouseOrTouchUsedTimer: number | undefined;\n let dismissTimer: number | undefined;\n let triggerKeys: Set<number> | undefined;\n let dismissKeys: Set<number> | undefined;\n\n if (props) {\n if (props.triggerKeys?.length) {\n triggerKeys = new Set(props.triggerKeys);\n }\n if (props.dismissKeys?.length) {\n dismissKeys = new Set(props.dismissKeys);\n }\n }\n\n const broadcast = (): void => {\n const refs = currentTargetWindow?.__keyborg?.refs;\n if (refs) {\n for (const id of Object.keys(refs)) {\n (refs[id] as KeyborgInternal)._notify(isNavigating);\n }\n }\n };\n\n const setNavigating = (val: boolean): void => {\n if (isNavigating !== val) {\n isNavigating = val;\n broadcast();\n }\n };\n\n const shouldTrigger = (e: KeyboardEvent): boolean => {\n // TODO Some rich text fields can allow Tab key for indentation so it\n // doesn't need to be a navigation key. If there is a bug regarding that\n // we should revisit.\n if (e.key === \"Tab\") {\n return true;\n }\n const active = currentTargetWindow?.document\n .activeElement as HTMLElement | null;\n const isTriggerKey = !triggerKeys || triggerKeys.has(e.keyCode);\n const isEditable =\n active &&\n (active.tagName === \"INPUT\" ||\n active.tagName === \"TEXTAREA\" ||\n active.isContentEditable);\n return isTriggerKey && !isEditable;\n };\n\n const shouldDismiss = (e: KeyboardEvent): boolean => {\n return !!dismissKeys?.has(e.keyCode);\n };\n\n const scheduleDismiss = (): void => {\n const targetWindow = currentTargetWindow;\n if (!targetWindow) {\n return;\n }\n if (dismissTimer) {\n targetWindow.clearTimeout(dismissTimer);\n dismissTimer = undefined;\n }\n const previousActiveElement = targetWindow.document.activeElement;\n dismissTimer = targetWindow.setTimeout(() => {\n dismissTimer = undefined;\n const currentActiveElement = targetWindow.document.activeElement;\n if (\n previousActiveElement &&\n currentActiveElement &&\n previousActiveElement === currentActiveElement\n ) {\n // Esc was pressed, currently focused element hasn't changed.\n // Just dismiss the keyboard navigation mode.\n setNavigating(false);\n }\n }, _dismissTimeout);\n };\n\n const onFocusIn = (e: KeyborgFocusInEvent): void => {\n // When the focus is moved not programmatically and without keydown events,\n // it is likely that the focus is moved by screen reader (as it might\n // swallow the events when the screen reader shortcuts are used). The\n // screen reader usage is keyboard navigation.\n if (isMouseOrTouchUsedTimer) {\n return;\n }\n if (isNavigating) {\n return;\n }\n const details = e.detail;\n if (!details.relatedTarget) {\n return;\n }\n if (\n details.isFocusedProgrammatically ||\n details.isFocusedProgrammatically === undefined\n ) {\n return;\n }\n setNavigating(true);\n };\n\n const onMouseOrTouch = (): void => {\n if (currentTargetWindow) {\n if (isMouseOrTouchUsedTimer) {\n currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);\n }\n isMouseOrTouchUsedTimer = currentTargetWindow.setTimeout(() => {\n isMouseOrTouchUsedTimer = undefined;\n }, 1000);\n }\n setNavigating(false);\n };\n\n const onMouseDown = (e: MouseEvent): void => {\n if (\n e.buttons === 0 ||\n (e.clientX === 0 && e.clientY === 0 && e.screenX === 0 && e.screenY === 0)\n ) {\n // This is most likely an event triggered by the screen reader to\n // perform an action on an element, do not dismiss the keyboard\n // navigation mode.\n return;\n }\n onMouseOrTouch();\n };\n\n const onKeyDown = (e: KeyboardEvent): void => {\n if (isNavigating) {\n if (shouldDismiss(e)) {\n scheduleDismiss();\n }\n } else if (shouldTrigger(e)) {\n setNavigating(true);\n }\n };\n\n const targetDocument = targetWindow.document;\n addEventListener(targetDocument, KEYBORG_FOCUSIN, onFocusIn as EventListener);\n addEventListener(targetDocument, \"mousedown\", onMouseDown as EventListener);\n addEventListener(targetWindow, \"keydown\", onKeyDown as EventListener);\n addEventListener(targetDocument, \"touchstart\", onMouseOrTouch);\n addEventListener(targetDocument, \"touchend\", onMouseOrTouch);\n addEventListener(targetDocument, \"touchcancel\", onMouseOrTouch);\n\n setupFocusEvent(targetWindow);\n\n const dispose = (): void => {\n if (!currentTargetWindow) {\n return;\n }\n if (isMouseOrTouchUsedTimer) {\n currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);\n isMouseOrTouchUsedTimer = undefined;\n }\n if (dismissTimer) {\n currentTargetWindow.clearTimeout(dismissTimer);\n dismissTimer = undefined;\n }\n disposeFocusEvent(currentTargetWindow);\n const targetDocument = currentTargetWindow.document;\n removeEventListener(\n targetDocument,\n KEYBORG_FOCUSIN,\n onFocusIn as EventListener,\n );\n removeEventListener(\n targetDocument,\n \"mousedown\",\n onMouseDown as EventListener,\n );\n removeEventListener(\n currentTargetWindow,\n \"keydown\",\n onKeyDown as EventListener,\n );\n removeEventListener(targetDocument, \"touchstart\", onMouseOrTouch);\n removeEventListener(targetDocument, \"touchend\", onMouseOrTouch);\n removeEventListener(targetDocument, \"touchcancel\", onMouseOrTouch);\n currentTargetWindow = undefined;\n };\n\n return {\n dispose,\n getNavigating: () => isNavigating,\n setNavigating,\n };\n}\n\nexport function createKeyborg(win: Window, props?: KeyborgProps): Keyborg {\n const kwin = win as WindowWithKeyborg;\n const id = \"k\" + ++_lastId;\n let localWin: WindowWithKeyborg | undefined = kwin;\n let core: KeyborgCoreHandle | undefined;\n let callbacks: KeyborgCallback[] = [];\n\n const existing = kwin.__keyborg;\n if (existing) {\n core = existing.core;\n } else {\n core = createKeyborgCore(kwin, props);\n }\n\n const instance: KeyborgInternal = {\n isNavigatingWithKeyboard() {\n return !!core?.getNavigating();\n },\n subscribe(callback) {\n callbacks.push(callback);\n },\n unsubscribe(callback) {\n const index = callbacks.indexOf(callback);\n if (index >= 0) {\n callbacks.splice(index, 1);\n }\n },\n setVal(val) {\n core?.setNavigating(val);\n },\n _notify(val) {\n callbacks.forEach((cb) => cb(val));\n },\n _dispose() {\n const wkb = localWin?.__keyborg;\n if (wkb?.refs[id]) {\n delete wkb.refs[id];\n if (Object.keys(wkb.refs).length === 0) {\n wkb.core.dispose();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n delete localWin!.__keyborg;\n }\n } else if (process.env.NODE_ENV !== \"production\") {\n console.error(`Keyborg instance ${id} is being disposed incorrectly.`);\n }\n callbacks = [];\n core = undefined;\n localWin = undefined;\n },\n };\n\n if (existing) {\n existing.refs[id] = instance;\n } else {\n kwin.__keyborg = {\n core,\n refs: { [id]: instance },\n };\n }\n\n return instance;\n}\n\nexport function disposeKeyborg(instance: Keyborg): void {\n (instance as KeyborgInternal)._dispose();\n}\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport type { Keyborg, KeyborgCallback } from \"./Keyborg.mts\";\nexport { createKeyborg, disposeKeyborg } from \"./Keyborg.mts\";\n\nexport type {\n KeyborgFocusInEvent,\n KeyborgFocusInEventDetails,\n KeyborgFocusOutEvent,\n KeyborgFocusOutEventDetails,\n} from \"./FocusEvent.mts\";\nexport {\n getLastFocusedProgrammatically,\n nativeFocus,\n KEYBORG_FOCUSIN,\n KEYBORG_FOCUSOUT,\n} from \"./FocusEvent.mts\";\n\nexport const version = process.env.PKG_VERSION;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/dom.mts","../src/FocusEvent.mts","../src/Keyborg.mts","../src/index.mts"],"sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// All keyborg listeners use the capture phase; centralizing the calls lets the\n// minifier collapse the repeated DOM method names into a single short-named\n// import binding.\nexport const addEventListener = (\n target: EventTarget,\n type: string,\n handler: EventListener,\n): void => {\n target.addEventListener(type, handler, true);\n};\n\nexport const removeEventListener = (\n target: EventTarget,\n type: string,\n handler: EventListener,\n): void => {\n target.removeEventListener(type, handler, true);\n};\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { addEventListener, removeEventListener } from \"./dom.mts\";\n\nexport const KEYBORG_FOCUSIN = \"keyborg:focusin\";\nexport const KEYBORG_FOCUSOUT = \"keyborg:focusout\";\n\ninterface KeyborgFocus {\n /**\n * This is the native `focus` function that is retained so that it can be restored when keyborg is disposed\n */\n __keyborgNativeFocus?: (options?: FocusOptions | undefined) => void;\n}\n\n// Internal data stored on `window.__keyborgData` as a tuple. Nothing outside\n// this module reads these slots, so a tuple drops the property-name strings\n// from the minified output — the indexes below inline as numeric literals.\nconst FOCUS_IN_HANDLER = 0;\nconst FOCUS_OUT_HANDLER = 1;\nconst SHADOW_TARGETS = 2;\nconst LAST_FOCUSED_PROGRAMMATICALLY = 3;\ntype KeyborgFocusEventData = [\n (e: FocusEvent) => void,\n (e: FocusEvent) => void,\n Set<WeakRef<ShadowRoot>>,\n WeakRef<HTMLElement>?,\n];\n\n/**\n * Extends the global window with keyborg focus event data\n */\ninterface WindowWithKeyborgFocusEvent extends Window {\n HTMLElement: typeof HTMLElement;\n __keyborgData?: KeyborgFocusEventData;\n}\n\nfunction canOverrideNativeFocus(win: Window): boolean {\n const HTMLElement = (win as WindowWithKeyborgFocusEvent).HTMLElement;\n const origFocus = HTMLElement.prototype.focus;\n\n let isCustomFocusCalled = false;\n\n HTMLElement.prototype.focus = function focus(): void {\n isCustomFocusCalled = true;\n };\n\n const btn = win.document.createElement(\"button\");\n\n btn.focus();\n\n HTMLElement.prototype.focus = origFocus;\n\n return isCustomFocusCalled;\n}\n\nlet _canOverrideNativeFocus = false;\n\nexport interface KeyborgFocusInEventDetails {\n relatedTarget?: HTMLElement;\n isFocusedProgrammatically?: boolean;\n originalEvent?: FocusEvent;\n}\n\nexport interface KeyborgFocusInEvent extends CustomEvent<KeyborgFocusInEventDetails> {\n /**\n * @deprecated - used `event.detail`\n */\n details?: KeyborgFocusInEventDetails;\n}\n\nexport interface KeyborgFocusOutEventDetails {\n originalEvent: FocusEvent;\n}\n\nexport type KeyborgFocusOutEvent = CustomEvent<KeyborgFocusOutEventDetails>;\n\n/**\n * Guarantees that the native `focus` will be used\n */\nexport function nativeFocus(element: HTMLElement): void {\n const focus = element.focus as KeyborgFocus;\n\n if (focus.__keyborgNativeFocus) {\n focus.__keyborgNativeFocus.call(element);\n } else {\n element.focus();\n }\n}\n\n/**\n * Overrides the native `focus` and setups the keyborg focus event\n */\nexport function setupFocusEvent(win: Window): void {\n const kwin = win as WindowWithKeyborgFocusEvent;\n const doc = kwin.document;\n const proto = kwin.HTMLElement.prototype;\n\n if (!_canOverrideNativeFocus) {\n _canOverrideNativeFocus = canOverrideNativeFocus(kwin);\n }\n\n const origFocus = proto.focus;\n\n if ((origFocus as KeyborgFocus).__keyborgNativeFocus) {\n // Already set up.\n return;\n }\n\n proto.focus = focus;\n\n const shadowTargets: Set<WeakRef<ShadowRoot>> = new Set();\n\n const focusOutHandler = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n\n if (!target) {\n return;\n }\n\n const event: KeyborgFocusOutEvent = new CustomEvent(KEYBORG_FOCUSOUT, {\n cancelable: true,\n bubbles: true,\n // Allows the event to bubble past an open shadow root\n composed: true,\n detail: {\n originalEvent: e,\n },\n });\n\n target.dispatchEvent(event);\n };\n\n const focusInHandler = (e: FocusEvent) => {\n const target = e.target as HTMLElement;\n\n if (!target) {\n return;\n }\n\n let node: Node | null | undefined = e.composedPath()[0] as\n | Node\n | null\n | undefined;\n\n const currentShadows: Set<ShadowRoot> = new Set();\n\n while (node) {\n if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\n currentShadows.add(node as ShadowRoot);\n node = (node as ShadowRoot).host;\n } else {\n node = node.parentNode;\n }\n }\n\n for (const shadowRootWeakRef of shadowTargets) {\n const shadowRoot = shadowRootWeakRef.deref();\n\n if (!shadowRoot || !currentShadows.has(shadowRoot)) {\n shadowTargets.delete(shadowRootWeakRef);\n\n if (shadowRoot) {\n removeEventListener(shadowRoot, \"focusin\", focusInHandler);\n removeEventListener(shadowRoot, \"focusout\", focusOutHandler);\n }\n }\n }\n\n onFocusIn(target, (e.relatedTarget as HTMLElement | null) || undefined);\n };\n\n const onFocusIn = (\n target: Element,\n relatedTarget?: HTMLElement,\n originalEvent?: FocusEvent,\n ) => {\n const shadowRoot = target.shadowRoot;\n\n if (shadowRoot) {\n /**\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1512028\n * focusin events don't bubble up through an open shadow root once focus is inside\n * once focus moves into a shadow root - we drop the same focusin handler there\n * keyborg's custom event will still bubble up since it is composed\n * event handlers should be cleaned up once focus leaves the shadow root.\n *\n * When a focusin event is dispatched from a shadow root, its target is the shadow root parent.\n * Each shadow root encounter requires a new capture listener.\n * Why capture? - we want to follow the focus event in order or descending nested shadow roots\n * When there are no more shadow root targets - dispatch the keyborg:focusin event\n *\n * 1. no focus event\n * > document - capture listener ✅\n * > shadow root 1\n * > shadow root 2\n * > shadow root 3\n * > focused element\n *\n * 2. focus event received by document listener\n * > document - capture listener ✅ (focus event here)\n * > shadow root 1 - capture listener ✅\n * > shadow root 2\n * > shadow root 3\n * > focused element\n *\n * 3. focus event received by root l1 listener\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅ (focus event here)\n * > shadow root 2 - capture listener ✅\n * > shadow root 3\n * > focused element\n *\n * 4. focus event received by root l2 listener\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅\n * > shadow root 2 - capture listener ✅ (focus event here)\n * > shadow root 3 - capture listener ✅\n * > focused element\n *\n * 5. focus event received by root l3 listener, no more shadow root targets\n * > document - capture listener ✅\n * > shadow root 1 - capture listener ✅\n * > shadow root 2 - capture listener ✅\n * > shadow root 3 - capture listener ✅ (focus event here)\n * > focused element ✅ (no shadow root - dispatch keyborg event)\n */\n\n for (const shadowRootWeakRef of shadowTargets) {\n if (shadowRootWeakRef.deref() === shadowRoot) {\n return;\n }\n }\n\n addEventListener(shadowRoot, \"focusin\", focusInHandler);\n addEventListener(shadowRoot, \"focusout\", focusOutHandler);\n\n shadowTargets.add(new WeakRef(shadowRoot));\n\n return;\n }\n\n const details: KeyborgFocusInEventDetails = {\n relatedTarget,\n originalEvent,\n };\n\n const event: KeyborgFocusInEvent = new CustomEvent(KEYBORG_FOCUSIN, {\n cancelable: true,\n bubbles: true,\n // Allows the event to bubble past an open shadow root\n composed: true,\n detail: details,\n });\n\n // Tabster (and other users) can still use the legacy details field - keeping for backwards compat\n event.details = details;\n\n if (_canOverrideNativeFocus || data[LAST_FOCUSED_PROGRAMMATICALLY]) {\n details.isFocusedProgrammatically =\n target === data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref();\n\n data[LAST_FOCUSED_PROGRAMMATICALLY] = undefined;\n }\n\n target.dispatchEvent(event);\n };\n\n const data: KeyborgFocusEventData = [\n focusInHandler,\n focusOutHandler,\n shadowTargets,\n ];\n kwin.__keyborgData = data;\n\n addEventListener(doc, \"focusin\", focusInHandler);\n addEventListener(doc, \"focusout\", focusOutHandler);\n\n function focus(this: HTMLElement) {\n const d = (kwin as WindowWithKeyborgFocusEvent).__keyborgData;\n\n if (d) {\n d[LAST_FOCUSED_PROGRAMMATICALLY] = new WeakRef(this);\n }\n\n // eslint-disable-next-line prefer-rest-params\n return origFocus.apply(this, arguments);\n }\n\n let activeElement = doc.activeElement as Element | null;\n\n // If keyborg is created with the focus inside shadow root, we need\n // to go through the shadows up to make sure all relevant shadows\n // have focus handlers attached.\n while (activeElement && activeElement.shadowRoot) {\n onFocusIn(activeElement);\n activeElement = activeElement.shadowRoot.activeElement;\n }\n\n (focus as KeyborgFocus).__keyborgNativeFocus = origFocus;\n}\n\n/**\n * Removes keyborg event listeners and custom focus override\n * @param win The window that stores keyborg focus events\n */\nexport function disposeFocusEvent(win: Window): void {\n const kwin = win as WindowWithKeyborgFocusEvent;\n const proto = kwin.HTMLElement.prototype;\n const origFocus = (proto.focus as KeyborgFocus).__keyborgNativeFocus;\n const data = kwin.__keyborgData;\n\n if (data) {\n const doc = kwin.document;\n removeEventListener(doc, \"focusin\", data[FOCUS_IN_HANDLER]);\n removeEventListener(doc, \"focusout\", data[FOCUS_OUT_HANDLER]);\n\n for (const shadowRootWeakRef of data[SHADOW_TARGETS]) {\n const shadowRoot = shadowRootWeakRef.deref();\n\n if (shadowRoot) {\n removeEventListener(shadowRoot, \"focusin\", data[FOCUS_IN_HANDLER]);\n removeEventListener(shadowRoot, \"focusout\", data[FOCUS_OUT_HANDLER]);\n }\n }\n\n data[SHADOW_TARGETS].clear();\n\n delete kwin.__keyborgData;\n }\n\n if (origFocus) {\n proto.focus = origFocus;\n }\n}\n\n/**\n * @param win The window that stores keyborg focus events\n * @returns The last element focused with element.focus()\n */\nexport function getLastFocusedProgrammatically(\n win: Window,\n): HTMLElement | null | undefined {\n const data = (win as WindowWithKeyborgFocusEvent).__keyborgData;\n\n return data\n ? data[LAST_FOCUSED_PROGRAMMATICALLY]?.deref() || null\n : undefined;\n}\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { addEventListener, removeEventListener } from \"./dom.mts\";\nimport {\n disposeFocusEvent,\n KeyborgFocusInEvent,\n KEYBORG_FOCUSIN,\n setupFocusEvent,\n} from \"./FocusEvent.mts\";\n\ninterface WindowWithKeyborg extends Window {\n __keyborg?: {\n core: KeyborgCoreHandle;\n refs: { [id: string]: Keyborg };\n };\n}\n\n// When a key from dismissKeys is pressed and the focus is not moved during\n// _dismissTimeout ms, keyboard navigation mode is dismissed.\nconst _dismissTimeout = 500;\n\nlet _lastId = 0;\n\nexport interface KeyborgProps {\n // Keys to be used to trigger keyboard navigation mode. By default, any key\n // will trigger it. Could be limited to, for example, just Tab (or Tab and\n // arrow keys).\n triggerKeys?: number[];\n // Keys to be used to dismiss keyboard navigation mode using keyboard (in\n // addition to mouse clicks which dismiss it). For example, Esc could be used\n // to dismiss.\n dismissKeys?: number[];\n}\n\nexport type KeyborgCallback = (isNavigatingWithKeyboard: boolean) => void;\n\n/**\n * Internal handle for the per-window core state. Not part of the public API.\n *\n * Shape is part of the `__keyborg.core` slot contract: when multiple keyborg\n * majors share the same window, the second loader reads `core` set by the\n * first. Keep `isNavigatingWithKeyboard` as a writable property accessor and\n * `dispose()` as a method so older majors can still read/write state without\n * TypeError. Changes here are breaking for that interop.\n */\ninterface KeyborgCoreHandle {\n isNavigatingWithKeyboard: boolean;\n dispose(): void;\n}\n\n/**\n * Used to determine the keyboard navigation state.\n */\nexport interface Keyborg {\n /**\n * @returns Whether the user is navigating with keyboard\n */\n isNavigatingWithKeyboard(): boolean;\n /**\n * @param callback - Called when the keyboard navigation state changes\n */\n subscribe(callback: KeyborgCallback): void;\n /**\n * @param callback - Registered with subscribe\n */\n unsubscribe(callback: KeyborgCallback): void;\n /**\n * Manually set the keyboard navigation state\n */\n setVal(isNavigatingWithKeyboard: boolean): void;\n}\n\n// Augments the public Keyborg with internal members that also form the\n// `__keyborg.refs` slot wire protocol. The shape — `_cb` callback array and\n// `dispose()` method — matches keyborg <= 2.6.0's `Keyborg` class so that\n// mixed-version environments can broadcast and tear down each other's\n// instances without TypeError. Changes here are breaking for that interop.\ninterface KeyborgInternal extends Keyborg {\n _cb: KeyborgCallback[];\n dispose(): void;\n}\n\nfunction createKeyborgCore(\n targetWindow: WindowWithKeyborg,\n props?: KeyborgProps,\n): KeyborgCoreHandle {\n let currentTargetWindow: WindowWithKeyborg | undefined = targetWindow;\n let isNavigating = false;\n let isMouseOrTouchUsedTimer: number | undefined;\n let dismissTimer: number | undefined;\n let triggerKeys: Set<number> | undefined;\n let dismissKeys: Set<number> | undefined;\n\n if (props) {\n if (props.triggerKeys?.length) {\n triggerKeys = new Set(props.triggerKeys);\n }\n if (props.dismissKeys?.length) {\n dismissKeys = new Set(props.dismissKeys);\n }\n }\n\n const broadcast = (): void => {\n const refs = currentTargetWindow?.__keyborg?.refs;\n if (refs) {\n for (const id of Object.keys(refs)) {\n (refs[id] as KeyborgInternal)._cb.forEach((cb) => cb(isNavigating));\n }\n }\n };\n\n const setNavigating = (val: boolean): void => {\n if (isNavigating !== val) {\n isNavigating = val;\n broadcast();\n }\n };\n\n const shouldTrigger = (e: KeyboardEvent): boolean => {\n // TODO Some rich text fields can allow Tab key for indentation so it\n // doesn't need to be a navigation key. If there is a bug regarding that\n // we should revisit.\n if (e.key === \"Tab\") {\n return true;\n }\n const active = currentTargetWindow?.document\n .activeElement as HTMLElement | null;\n const isTriggerKey = !triggerKeys || triggerKeys.has(e.keyCode);\n const isEditable =\n active &&\n (active.tagName === \"INPUT\" ||\n active.tagName === \"TEXTAREA\" ||\n active.isContentEditable);\n return isTriggerKey && !isEditable;\n };\n\n const shouldDismiss = (e: KeyboardEvent): boolean => {\n return !!dismissKeys?.has(e.keyCode);\n };\n\n const scheduleDismiss = (): void => {\n const targetWindow = currentTargetWindow;\n if (!targetWindow) {\n return;\n }\n if (dismissTimer) {\n targetWindow.clearTimeout(dismissTimer);\n dismissTimer = undefined;\n }\n const previousActiveElement = targetWindow.document.activeElement;\n dismissTimer = targetWindow.setTimeout(() => {\n dismissTimer = undefined;\n const currentActiveElement = targetWindow.document.activeElement;\n if (\n previousActiveElement &&\n currentActiveElement &&\n previousActiveElement === currentActiveElement\n ) {\n // Esc was pressed, currently focused element hasn't changed.\n // Just dismiss the keyboard navigation mode.\n setNavigating(false);\n }\n }, _dismissTimeout);\n };\n\n const onFocusIn = (e: KeyborgFocusInEvent): void => {\n // When the focus is moved not programmatically and without keydown events,\n // it is likely that the focus is moved by screen reader (as it might\n // swallow the events when the screen reader shortcuts are used). The\n // screen reader usage is keyboard navigation.\n if (isMouseOrTouchUsedTimer) {\n return;\n }\n if (isNavigating) {\n return;\n }\n const details = e.detail;\n if (!details.relatedTarget) {\n return;\n }\n if (\n details.isFocusedProgrammatically ||\n details.isFocusedProgrammatically === undefined\n ) {\n return;\n }\n setNavigating(true);\n };\n\n const onMouseOrTouch = (): void => {\n if (currentTargetWindow) {\n if (isMouseOrTouchUsedTimer) {\n currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);\n }\n isMouseOrTouchUsedTimer = currentTargetWindow.setTimeout(() => {\n isMouseOrTouchUsedTimer = undefined;\n }, 1000);\n }\n setNavigating(false);\n };\n\n const onMouseDown = (e: MouseEvent): void => {\n if (\n e.buttons === 0 ||\n (e.clientX === 0 && e.clientY === 0 && e.screenX === 0 && e.screenY === 0)\n ) {\n // This is most likely an event triggered by the screen reader to\n // perform an action on an element, do not dismiss the keyboard\n // navigation mode.\n return;\n }\n onMouseOrTouch();\n };\n\n const onKeyDown = (e: KeyboardEvent): void => {\n if (isNavigating) {\n if (shouldDismiss(e)) {\n scheduleDismiss();\n }\n } else if (shouldTrigger(e)) {\n setNavigating(true);\n }\n };\n\n const targetDocument = targetWindow.document;\n addEventListener(targetDocument, KEYBORG_FOCUSIN, onFocusIn as EventListener);\n addEventListener(targetDocument, \"mousedown\", onMouseDown as EventListener);\n addEventListener(targetWindow, \"keydown\", onKeyDown as EventListener);\n addEventListener(targetDocument, \"touchstart\", onMouseOrTouch);\n addEventListener(targetDocument, \"touchend\", onMouseOrTouch);\n addEventListener(targetDocument, \"touchcancel\", onMouseOrTouch);\n\n setupFocusEvent(targetWindow);\n\n const dispose = (): void => {\n if (!currentTargetWindow) {\n return;\n }\n if (isMouseOrTouchUsedTimer) {\n currentTargetWindow.clearTimeout(isMouseOrTouchUsedTimer);\n isMouseOrTouchUsedTimer = undefined;\n }\n if (dismissTimer) {\n currentTargetWindow.clearTimeout(dismissTimer);\n dismissTimer = undefined;\n }\n disposeFocusEvent(currentTargetWindow);\n const targetDocument = currentTargetWindow.document;\n removeEventListener(\n targetDocument,\n KEYBORG_FOCUSIN,\n onFocusIn as EventListener,\n );\n removeEventListener(\n targetDocument,\n \"mousedown\",\n onMouseDown as EventListener,\n );\n removeEventListener(\n currentTargetWindow,\n \"keydown\",\n onKeyDown as EventListener,\n );\n removeEventListener(targetDocument, \"touchstart\", onMouseOrTouch);\n removeEventListener(targetDocument, \"touchend\", onMouseOrTouch);\n removeEventListener(targetDocument, \"touchcancel\", onMouseOrTouch);\n currentTargetWindow = undefined;\n };\n\n return {\n dispose,\n get isNavigatingWithKeyboard() {\n return isNavigating;\n },\n set isNavigatingWithKeyboard(val: boolean) {\n setNavigating(val);\n },\n };\n}\n\nexport function createKeyborg(win: Window, props?: KeyborgProps): Keyborg {\n const kwin = win as WindowWithKeyborg;\n const id = \"k\" + ++_lastId;\n let localWin: WindowWithKeyborg | undefined = kwin;\n let core: KeyborgCoreHandle | undefined;\n // `callbacks` is exposed as `instance._cb` to satisfy the slot wire\n // protocol. We mutate the array in place (push/splice/length=0) so the\n // reference stays stable for foreign-version broadcasts.\n const callbacks: KeyborgCallback[] = [];\n\n const existing = kwin.__keyborg;\n if (existing) {\n core = existing.core;\n } else {\n core = createKeyborgCore(kwin, props);\n }\n\n const instance: KeyborgInternal = {\n isNavigatingWithKeyboard() {\n return !!core?.isNavigatingWithKeyboard;\n },\n subscribe(callback) {\n callbacks.push(callback);\n },\n unsubscribe(callback) {\n const index = callbacks.indexOf(callback);\n if (index >= 0) {\n callbacks.splice(index, 1);\n }\n },\n setVal(val) {\n if (core) {\n core.isNavigatingWithKeyboard = val;\n }\n },\n _cb: callbacks,\n dispose() {\n const wkb = localWin?.__keyborg;\n if (wkb?.refs[id]) {\n delete wkb.refs[id];\n if (Object.keys(wkb.refs).length === 0) {\n wkb.core.dispose();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n delete localWin!.__keyborg;\n }\n } else if (process.env.NODE_ENV !== \"production\") {\n console.error(`Keyborg instance ${id} is being disposed incorrectly.`);\n }\n callbacks.length = 0;\n core = undefined;\n localWin = undefined;\n },\n };\n\n if (existing) {\n existing.refs[id] = instance;\n } else {\n kwin.__keyborg = {\n core,\n refs: { [id]: instance },\n };\n }\n\n return instance;\n}\n\nexport function disposeKeyborg(instance: Keyborg): void {\n (instance as KeyborgInternal).dispose();\n}\n","/*!\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport type { Keyborg, KeyborgCallback } from \"./Keyborg.mts\";\nexport { createKeyborg, disposeKeyborg } from \"./Keyborg.mts\";\n\nexport type {\n KeyborgFocusInEvent,\n KeyborgFocusInEventDetails,\n KeyborgFocusOutEvent,\n KeyborgFocusOutEventDetails,\n} from \"./FocusEvent.mts\";\nexport {\n getLastFocusedProgrammatically,\n nativeFocus,\n KEYBORG_FOCUSIN,\n KEYBORG_FOCUSOUT,\n} from \"./FocusEvent.mts\";\n\nexport const version = process.env.PKG_VERSION;\n"],"mappings":"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"}
|