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 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]._notify(isNavigating);
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
- getNavigating: () => isNavigating,
328
- setNavigating
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
- let callbacks = [];
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?.getNavigating();
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?.setNavigating(val);
353
- },
354
- _notify(val) {
355
- callbacks.forEach((cb) => cb(val));
356
+ if (core) core.isNavigatingWithKeyboard = val;
356
357
  },
357
- _dispose() {
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._dispose();
381
+ instance.dispose();
380
382
  }
381
383
 
382
384
  //#endregion
383
385
  //#region src/index.mts
384
- const version = "2.14.0";
386
+ const version = "2.14.1";
385
387
 
386
388
  //#endregion
387
389
  exports.KEYBORG_FOCUSIN = KEYBORG_FOCUSIN;
@@ -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]._notify(isNavigating);
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
- getNavigating: () => isNavigating,
326
- setNavigating
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
- let callbacks = [];
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?.getNavigating();
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?.setNavigating(val);
351
- },
352
- _notify(val) {
353
- callbacks.forEach((cb) => cb(val));
354
+ if (core) core.isNavigatingWithKeyboard = val;
354
355
  },
355
- _dispose() {
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._dispose();
379
+ instance.dispose();
378
380
  }
379
381
 
380
382
  //#endregion
381
383
  //#region src/index.mts
382
- const version = "2.14.0";
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":";;;;;AAQA,MAAa,oBACX,QACA,MACA,YACS;AACT,QAAO,iBAAiB,MAAM,SAAS,KAAK;;AAG9C,MAAa,uBACX,QACA,MACA,YACS;AACT,QAAO,oBAAoB,MAAM,SAAS,KAAK;;;;;;;;;ACdjD,MAAa,kBAAkB;AAC/B,MAAa,mBAAmB;AAYhC,MAAM,mBAAmB;AACzB,MAAM,oBAAoB;AAC1B,MAAM,iBAAiB;AACvB,MAAM,gCAAgC;AAgBtC,SAAS,uBAAuB,KAAsB;CACpD,MAAM,cAAe,IAAoC;CACzD,MAAM,YAAY,YAAY,UAAU;CAExC,IAAI,sBAAsB;AAE1B,aAAY,UAAU,QAAQ,SAAS,QAAc;AACnD,wBAAsB;;AAKxB,CAFY,IAAI,SAAS,cAAc,SAAS,CAE5C,OAAO;AAEX,aAAY,UAAU,QAAQ;AAE9B,QAAO;;AAGT,IAAI,0BAA0B;;;;AAwB9B,SAAgB,YAAY,SAA4B;CACtD,MAAM,QAAQ,QAAQ;AAEtB,KAAI,MAAM,qBACR,OAAM,qBAAqB,KAAK,QAAQ;KAExC,SAAQ,OAAO;;;;;AAOnB,SAAgB,gBAAgB,KAAmB;CACjD,MAAM,OAAO;CACb,MAAM,MAAM,KAAK;CACjB,MAAM,QAAQ,KAAK,YAAY;AAE/B,KAAI,CAAC,wBACH,2BAA0B,uBAAuB,KAAK;CAGxD,MAAM,YAAY,MAAM;AAExB,KAAK,UAA2B,qBAE9B;AAGF,OAAM,QAAQ;CAEd,MAAM,gCAA0C,IAAI,KAAK;CAEzD,MAAM,mBAAmB,MAAkB;EACzC,MAAM,SAAS,EAAE;AAEjB,MAAI,CAAC,OACH;EAGF,MAAM,QAA8B,IAAI,YAAY,kBAAkB;GACpE,YAAY;GACZ,SAAS;GAET,UAAU;GACV,QAAQ,EACN,eAAe,GAChB;GACF,CAAC;AAEF,SAAO,cAAc,MAAM;;CAG7B,MAAM,kBAAkB,MAAkB;EACxC,MAAM,SAAS,EAAE;AAEjB,MAAI,CAAC,OACH;EAGF,IAAI,OAAgC,EAAE,cAAc,CAAC;EAKrD,MAAM,iCAAkC,IAAI,KAAK;AAEjD,SAAO,KACL,KAAI,KAAK,aAAa,KAAK,wBAAwB;AACjD,kBAAe,IAAI,KAAmB;AACtC,UAAQ,KAAoB;QAE5B,QAAO,KAAK;AAIhB,OAAK,MAAM,qBAAqB,eAAe;GAC7C,MAAM,aAAa,kBAAkB,OAAO;AAE5C,OAAI,CAAC,cAAc,CAAC,eAAe,IAAI,WAAW,EAAE;AAClD,kBAAc,OAAO,kBAAkB;AAEvC,QAAI,YAAY;AACd,yBAAoB,YAAY,WAAW,eAAe;AAC1D,yBAAoB,YAAY,YAAY,gBAAgB;;;;AAKlE,YAAU,QAAS,EAAE,iBAAwC,OAAU;;CAGzE,MAAM,aACJ,QACA,eACA,kBACG;EACH,MAAM,aAAa,OAAO;AAE1B,MAAI,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDd,QAAK,MAAM,qBAAqB,cAC9B,KAAI,kBAAkB,OAAO,KAAK,WAChC;AAIJ,oBAAiB,YAAY,WAAW,eAAe;AACvD,oBAAiB,YAAY,YAAY,gBAAgB;AAEzD,iBAAc,IAAI,IAAI,QAAQ,WAAW,CAAC;AAE1C;;EAGF,MAAM,UAAsC;GAC1C;GACA;GACD;EAED,MAAM,QAA6B,IAAI,YAAY,iBAAiB;GAClE,YAAY;GACZ,SAAS;GAET,UAAU;GACV,QAAQ;GACT,CAAC;AAGF,QAAM,UAAU;AAEhB,MAAI,2BAA2B,KAAK,gCAAgC;AAClE,WAAQ,4BACN,WAAW,KAAK,gCAAgC,OAAO;AAEzD,QAAK,iCAAiC;;AAGxC,SAAO,cAAc,MAAM;;CAG7B,MAAM,OAA8B;EAClC;EACA;EACA;EACD;AACD,MAAK,gBAAgB;AAErB,kBAAiB,KAAK,WAAW,eAAe;AAChD,kBAAiB,KAAK,YAAY,gBAAgB;CAElD,SAAS,QAAyB;EAChC,MAAM,IAAK,KAAqC;AAEhD,MAAI,EACF,GAAE,iCAAiC,IAAI,QAAQ,KAAK;AAItD,SAAO,UAAU,MAAM,MAAM,UAAU;;CAGzC,IAAI,gBAAgB,IAAI;AAKxB,QAAO,iBAAiB,cAAc,YAAY;AAChD,YAAU,cAAc;AACxB,kBAAgB,cAAc,WAAW;;AAG3C,CAAC,MAAuB,uBAAuB;;;;;;AAOjD,SAAgB,kBAAkB,KAAmB;CACnD,MAAM,OAAO;CACb,MAAM,QAAQ,KAAK,YAAY;CAC/B,MAAM,YAAa,MAAM,MAAuB;CAChD,MAAM,OAAO,KAAK;AAElB,KAAI,MAAM;EACR,MAAM,MAAM,KAAK;AACjB,sBAAoB,KAAK,WAAW,KAAK,kBAAkB;AAC3D,sBAAoB,KAAK,YAAY,KAAK,mBAAmB;AAE7D,OAAK,MAAM,qBAAqB,KAAK,iBAAiB;GACpD,MAAM,aAAa,kBAAkB,OAAO;AAE5C,OAAI,YAAY;AACd,wBAAoB,YAAY,WAAW,KAAK,kBAAkB;AAClE,wBAAoB,YAAY,YAAY,KAAK,mBAAmB;;;AAIxE,OAAK,gBAAgB,OAAO;AAE5B,SAAO,KAAK;;AAGd,KAAI,UACF,OAAM,QAAQ;;;;;;AAQlB,SAAgB,+BACd,KACgC;CAChC,MAAM,OAAQ,IAAoC;AAElD,QAAO,OACH,KAAK,gCAAgC,OAAO,IAAI,OAChD;;;;;;;;;ACvUN,MAAM,kBAAkB;AAExB,IAAI,UAAU;AA6Dd,SAAS,kBACP,cACA,OACmB;CACnB,IAAI,sBAAqD;CACzD,IAAI,eAAe;CACnB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AAEJ,KAAI,OAAO;AACT,MAAI,MAAM,aAAa,OACrB,eAAc,IAAI,IAAI,MAAM,YAAY;AAE1C,MAAI,MAAM,aAAa,OACrB,eAAc,IAAI,IAAI,MAAM,YAAY;;CAI5C,MAAM,kBAAwB;EAC5B,MAAM,OAAO,qBAAqB,WAAW;AAC7C,MAAI,KACF,MAAK,MAAM,MAAM,OAAO,KAAK,KAAK,CAChC,CAAC,KAAK,IAAwB,IAAI,SAAS,OAAO,GAAG,aAAa,CAAC;;CAKzE,MAAM,iBAAiB,QAAuB;AAC5C,MAAI,iBAAiB,KAAK;AACxB,kBAAe;AACf,cAAW;;;CAIf,MAAM,iBAAiB,MAA8B;AAInD,MAAI,EAAE,QAAQ,MACZ,QAAO;EAET,MAAM,SAAS,qBAAqB,SACjC;EACH,MAAM,eAAe,CAAC,eAAe,YAAY,IAAI,EAAE,QAAQ;EAC/D,MAAM,aACJ,WACC,OAAO,YAAY,WAClB,OAAO,YAAY,cACnB,OAAO;AACX,SAAO,gBAAgB,CAAC;;CAG1B,MAAM,iBAAiB,MAA8B;AACnD,SAAO,CAAC,CAAC,aAAa,IAAI,EAAE,QAAQ;;CAGtC,MAAM,wBAA8B;EAClC,MAAM,eAAe;AACrB,MAAI,CAAC,aACH;AAEF,MAAI,cAAc;AAChB,gBAAa,aAAa,aAAa;AACvC,kBAAe;;EAEjB,MAAM,wBAAwB,aAAa,SAAS;AACpD,iBAAe,aAAa,iBAAiB;AAC3C,kBAAe;GACf,MAAM,uBAAuB,aAAa,SAAS;AACnD,OACE,yBACA,wBACA,0BAA0B,qBAI1B,eAAc,MAAM;KAErB,gBAAgB;;CAGrB,MAAM,aAAa,MAAiC;AAKlD,MAAI,wBACF;AAEF,MAAI,aACF;EAEF,MAAM,UAAU,EAAE;AAClB,MAAI,CAAC,QAAQ,cACX;AAEF,MACE,QAAQ,6BACR,QAAQ,8BAA8B,OAEtC;AAEF,gBAAc,KAAK;;CAGrB,MAAM,uBAA6B;AACjC,MAAI,qBAAqB;AACvB,OAAI,wBACF,qBAAoB,aAAa,wBAAwB;AAE3D,6BAA0B,oBAAoB,iBAAiB;AAC7D,8BAA0B;MACzB,IAAK;;AAEV,gBAAc,MAAM;;CAGtB,MAAM,eAAe,MAAwB;AAC3C,MACE,EAAE,YAAY,KACb,EAAE,YAAY,KAAK,EAAE,YAAY,KAAK,EAAE,YAAY,KAAK,EAAE,YAAY,EAKxE;AAEF,kBAAgB;;CAGlB,MAAM,aAAa,MAA2B;AAC5C,MAAI,cACF;OAAI,cAAc,EAAE,CAClB,kBAAiB;aAEV,cAAc,EAAE,CACzB,eAAc,KAAK;;CAIvB,MAAM,iBAAiB,aAAa;AACpC,kBAAiB,gBAAgB,iBAAiB,UAA2B;AAC7E,kBAAiB,gBAAgB,aAAa,YAA6B;AAC3E,kBAAiB,cAAc,WAAW,UAA2B;AACrE,kBAAiB,gBAAgB,cAAc,eAAe;AAC9D,kBAAiB,gBAAgB,YAAY,eAAe;AAC5D,kBAAiB,gBAAgB,eAAe,eAAe;AAE/D,iBAAgB,aAAa;CAE7B,MAAM,gBAAsB;AAC1B,MAAI,CAAC,oBACH;AAEF,MAAI,yBAAyB;AAC3B,uBAAoB,aAAa,wBAAwB;AACzD,6BAA0B;;AAE5B,MAAI,cAAc;AAChB,uBAAoB,aAAa,aAAa;AAC9C,kBAAe;;AAEjB,oBAAkB,oBAAoB;EACtC,MAAM,iBAAiB,oBAAoB;AAC3C,sBACE,gBACA,iBACA,UACD;AACD,sBACE,gBACA,aACA,YACD;AACD,sBACE,qBACA,WACA,UACD;AACD,sBAAoB,gBAAgB,cAAc,eAAe;AACjE,sBAAoB,gBAAgB,YAAY,eAAe;AAC/D,sBAAoB,gBAAgB,eAAe,eAAe;AAClE,wBAAsB;;AAGxB,QAAO;EACL;EACA,IAAI,2BAA2B;AAC7B,UAAO;;EAET,IAAI,yBAAyB,KAAc;AACzC,iBAAc,IAAI;;EAErB;;AAGH,SAAgB,cAAc,KAAa,OAA+B;CACxE,MAAM,OAAO;CACb,MAAM,KAAK,MAAM,EAAE;CACnB,IAAI,WAA0C;CAC9C,IAAI;CAIJ,MAAM,YAA+B,EAAE;CAEvC,MAAM,WAAW,KAAK;AACtB,KAAI,SACF,QAAO,SAAS;KAEhB,QAAO,kBAAkB,MAAM,MAAM;CAGvC,MAAM,WAA4B;EAChC,2BAA2B;AACzB,UAAO,CAAC,CAAC,MAAM;;EAEjB,UAAU,UAAU;AAClB,aAAU,KAAK,SAAS;;EAE1B,YAAY,UAAU;GACpB,MAAM,QAAQ,UAAU,QAAQ,SAAS;AACzC,OAAI,SAAS,EACX,WAAU,OAAO,OAAO,EAAE;;EAG9B,OAAO,KAAK;AACV,OAAI,KACF,MAAK,2BAA2B;;EAGpC,KAAK;EACL,UAAU;GACR,MAAM,MAAM,UAAU;AACtB,OAAI,KAAK,KAAK,KAAK;AACjB,WAAO,IAAI,KAAK;AAChB,QAAI,OAAO,KAAK,IAAI,KAAK,CAAC,WAAW,GAAG;AACtC,SAAI,KAAK,SAAS;AAElB,YAAO,SAAU;;cAEV,QAAQ,IAAI,aAAa,aAClC,SAAQ,MAAM,oBAAoB,GAAG,iCAAiC;AAExE,aAAU,SAAS;AACnB,UAAO;AACP,cAAW;;EAEd;AAED,KAAI,SACF,UAAS,KAAK,MAAM;KAEpB,MAAK,YAAY;EACf;EACA,MAAM,GAAG,KAAK,UAAU;EACzB;AAGH,QAAO;;AAGT,SAAgB,eAAe,UAAyB;AACtD,CAAC,SAA6B,SAAS;;;;;ACzUzC,MAAa"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keyborg",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "Keyboard Navigation Detection for Web",
5
5
  "author": "Marat Abdullin <marata@microsoft.com>",
6
6
  "license": "MIT",