import { b as isParent, e as getDeepActiveElementInShadow } from './ui-64815a12.js';
import { i as isNonNullable } from './type-guard-adc244fd.js';

/**
 * It listens to the keyup event on the window and calls the appropriate method on the registered elements
 *
 * @property {KeyboardEventListener[]} listeners used to record listeners
 */
class KeyboardManager {
  /**
   * Manager init
   */
  constructor() {
    this.listeners = [];
    this.listenKeyPress();
  }
  /**
   * Add the given listener to the list of listeners.
   *
   * @param {KeyboardEventListener[]} listeners - The listener to register.
   * @returns {void}
   */
  register(listeners) {
    listeners.map((listener) => (listener.eventName || (listener.eventName = 'keyup')));
    this.listeners = this.listeners.concat(listeners);
  }
  /**
   * The function removes the listeners from the listeners array
   *
   * @param {KeyboardEventListener[]} listeners - KeyboardEventListener[]
   * @returns {void}
   */
  deregister(listeners) {
    this.listeners = this.listeners.filter((listener) => !listeners.includes(listener));
  }
  /**
   * > Listen for keyup events on the window, and if the code matches the keyCode of a listener,
   * invoke the listener's callback
   */
  listenKeyPress() {
    // eslint-disable-next-line no-restricted-globals
    document.addEventListener('keydown', (e) => {
      this.invokeListeners('keydown', e);
    });
    // listen keyup is waiting activeElement changed.
    // eslint-disable-next-line no-restricted-globals
    document.addEventListener('keyup', (e) => {
      this.invokeListeners('keyup', e);
    });
  }
  /**
   * We filter the listeners by the event name, then filter them by whether the key code matches the
   * listener's key code, and then invoke the callback function for each listener that matches
   *
   * @param {'keyup' | 'keydown'} eventName - The name of the event that was triggered.
   * @param {KeyboardEvent} event - KeyboardEvent - this is the event that is passed to the event
   * listener.
   */
  invokeListeners(eventName, event) {
    this.listeners
      .filter((listener) => listener.eventName === eventName && this.shouldInvokeListener(listener, event))
      .forEach((listener) => {
      if (listener.preventDefault) {
        event.preventDefault();
      }
      listener.callback(event);
    });
  }
  /**
   * > If the keyCode is accepted, and the activeElement is in the scope, and the activeElement is not
   * out of the scope, then invoke the listener
   *
   * @param {KeyboardEventListener} listener - KeyboardEventListener - the listener object that we're
   * checking
   * @param {KeyboardEvent} event - The keyboard event that triggered the listener.
   * @returns {boolean} - should invoke
   */
  shouldInvokeListener(listener, event) {
    let keyCode = '';
    if (event.code) {
      keyCode = event.code;
    }
    else if (event.key && event.key !== 'Unidentified') {
      keyCode = event.key;
    }
    let activeElementInScope = [];
    let activeElementOutScope = [];
    const isKeyCodeAccepted = Array.isArray(listener.keyCode)
      ? listener.keyCode.includes(keyCode)
      : listener.keyCode === keyCode;
    if (!isKeyCodeAccepted) {
      return false;
    }
    /* istanbul ignore next */
    if (typeof listener.activeElementInScope === 'function') {
      activeElementInScope = listener.activeElementInScope();
    }
    else if (typeof listener.activeElementInScope === 'object') {
      activeElementInScope = listener.activeElementInScope;
    }
    /* istanbul ignore next */
    if (typeof listener.activeElementOutScope === 'function') {
      activeElementOutScope = listener.activeElementOutScope();
    }
    else if (typeof listener.activeElementOutScope === 'object') {
      activeElementOutScope = listener.activeElementOutScope;
    }
    const isActiveElementInScope = listener.activeElementInScope
      ? activeElementInScope.some((element) => {
        // eslint-disable-next-line no-restricted-globals
        return isParent(getDeepActiveElementInShadow(document, true), element);
      })
      : true;
    if (!isActiveElementInScope) {
      return false;
    }
    const isActiveElementOutScope = listener.activeElementOutScope
      ? activeElementOutScope.every((element) => 
      // eslint-disable-next-line no-restricted-globals
      !isParent(getDeepActiveElementInShadow(document, true), element))
      : true;
    const isExpectedModifierPressed = isNonNullable(listener.modifierPressed)
      ? listener.modifierPressed === this.isModifierPressed(event)
      : true;
    const isExpectedShiftKeyPressed = isNonNullable(listener.shiftKey)
      ? listener.shiftKey === event.shiftKey
      : true;
    return (isKeyCodeAccepted &&
      isActiveElementInScope &&
      isActiveElementOutScope &&
      isExpectedModifierPressed &&
      isExpectedShiftKeyPressed);
  }
  /**
   * Checks if the platform modifier key (Meta on Mac, Ctrl on Windows) is pressed.
   *
   * @param {KeyboardEvent} e - The keyboard event to check.
   * @returns {boolean} - True if the platform modifier key is pressed, false otherwise.
   */
  isModifierPressed(e) {
    return /Mac|iPhone|iPad/.test(navigator.userAgent) ? e.metaKey : e.ctrlKey;
  }
}
const KeyboardManager$1 = new KeyboardManager();

export { KeyboardManager$1 as K };
