{"version":3,"file":"aria.mjs","sources":["../../../../packages/utils/aria.ts"],"sourcesContent":["import type { Nullable } from '@sgui-plus/utils/types'\r\nexport const EVENT_CODE = {\r\n  tab: 'Tab',\r\n  enter: 'Enter',\r\n  space: 'Space',\r\n  left: 'ArrowLeft', // 37\r\n  up: 'ArrowUp', // 38\r\n  right: 'ArrowRight', // 39\r\n  down: 'ArrowDown', // 40\r\n  esc: 'Escape',\r\n  delete: 'Delete',\r\n  backspace: 'Backspace',\r\n  numpadEnter: 'NumpadEnter',\r\n  pageUp: 'PageUp',\r\n  pageDown: 'PageDown',\r\n  home: 'Home',\r\n  end: 'End',\r\n}\r\n\r\nconst FOCUSABLE_ELEMENT_SELECTORS = `a[href],button:not([disabled]),button:not([hidden]),:not([tabindex=\"-1\"]),input:not([disabled]),input:not([type=\"hidden\"]),select:not([disabled]),textarea:not([disabled])`\r\n\r\n/**\r\n * Determine if the testing element is visible on screen no matter if its on the viewport or not\r\n */\r\nexport const isVisible = (element: HTMLElement) => {\r\n  if (process.env.NODE_ENV === 'test') return true\r\n  const computed = getComputedStyle(element)\r\n  // element.offsetParent won't work on fix positioned\r\n  // WARNING: potential issue here, going to need some expert advices on this issue\r\n  return computed.position === 'fixed' ? false : element.offsetParent !== null\r\n}\r\n\r\nexport const obtainAllFocusableElements = (\r\n  element: HTMLElement\r\n): HTMLElement[] => {\r\n  return Array.from(\r\n    element.querySelectorAll<HTMLElement>(FOCUSABLE_ELEMENT_SELECTORS)\r\n  ).filter((item: HTMLElement) => isFocusable(item) && isVisible(item))\r\n}\r\n\r\n/**\r\n * @desc Determine if target element is focusable\r\n * @param element {HTMLElement}\r\n * @returns {Boolean} true if it is focusable\r\n */\r\nexport const isFocusable = (element: HTMLElement): boolean => {\r\n  if (\r\n    element.tabIndex > 0 ||\r\n    (element.tabIndex === 0 && element.getAttribute('tabIndex') !== null)\r\n  ) {\r\n    return true\r\n  }\r\n  // HTMLButtonElement has disabled\r\n  if ((element as HTMLButtonElement).disabled) {\r\n    return false\r\n  }\r\n\r\n  switch (element.nodeName) {\r\n    case 'A': {\r\n      // casting current element to Specific HTMLElement in order to be more type precise\r\n      return (\r\n        !!(element as HTMLAnchorElement).href &&\r\n        (element as HTMLAnchorElement).rel !== 'ignore'\r\n      )\r\n    }\r\n    case 'INPUT': {\r\n      return !(\r\n        (element as HTMLInputElement).type === 'hidden' ||\r\n        (element as HTMLInputElement).type === 'file'\r\n      )\r\n    }\r\n    case 'BUTTON':\r\n    case 'SELECT':\r\n    case 'TEXTAREA': {\r\n      return true\r\n    }\r\n    default: {\r\n      return false\r\n    }\r\n  }\r\n}\r\n\r\n/**\r\n * @desc Set Attempt to set focus on the current node.\r\n * @param element\r\n *          The node to attempt to focus on.\r\n * @returns\r\n *  true if element is focused.\r\n */\r\nexport const attemptFocus = (element: HTMLElement): boolean => {\r\n  if (!isFocusable(element)) {\r\n    return false\r\n  }\r\n  Utils.IgnoreUtilFocusChanges = true\r\n  // Remove the old try catch block since there will be no error to be thrown\r\n  element.focus?.()\r\n  Utils.IgnoreUtilFocusChanges = false\r\n  return document.activeElement === element\r\n}\r\n\r\n/**\r\n * Trigger an event\r\n * mouseenter, mouseleave, mouseover, keyup, change, click, etc.\r\n * @param  {HTMLElement} elm\r\n * @param  {String} name\r\n * @param  {*} opts\r\n */\r\nexport const triggerEvent = function (\r\n  elm: HTMLElement,\r\n  name: string,\r\n  ...opts: Array<boolean>\r\n): HTMLElement {\r\n  let eventName: string\r\n\r\n  if (name.includes('mouse') || name.includes('click')) {\r\n    eventName = 'MouseEvents'\r\n  } else if (name.includes('key')) {\r\n    eventName = 'KeyboardEvent'\r\n  } else {\r\n    eventName = 'HTMLEvents'\r\n  }\r\n  const evt = document.createEvent(eventName)\r\n\r\n  evt.initEvent(name, ...opts)\r\n  elm.dispatchEvent(evt)\r\n  return elm\r\n}\r\n\r\nexport const isLeaf = (sg: HTMLElement) => !sg.getAttribute('aria-owns')\r\n\r\nexport const getSibling = (\r\n  sg: HTMLElement,\r\n  distance: number,\r\n  elClass: string\r\n): Nullable<Element> => {\r\n  const { parentNode } = sg\r\n  if (!parentNode) return null\r\n  const siblings = parentNode.querySelectorAll(elClass)\r\n  const index = Array.prototype.indexOf.call(siblings, sg)\r\n  return siblings[index + distance] || null\r\n}\r\n\r\nexport const focusNode = (sg) => {\r\n  if (!sg) return\r\n  sg.focus()\r\n  !isLeaf(sg) && sg.click()\r\n}\r\n\r\nconst Utils = {\r\n  IgnoreUtilFocusChanges: false,\r\n  /**\r\n   * @desc Set focus on descendant nodes until the first focusable element is\r\n   *       found.\r\n   * @param {HTMLElement} element\r\n   *          DOM node for which to find the first focusable descendant.\r\n   * @returns {Boolean}\r\n   *  true if a focusable element is found and focus is set.\r\n   */\r\n  focusFirstDescendant(element: HTMLElement): boolean {\r\n    for (let i = 0; i < element.childNodes.length; i++) {\r\n      const child = element.childNodes[i] as HTMLElement\r\n      if (attemptFocus(child) || this.focusFirstDescendant(child)) {\r\n        return true\r\n      }\r\n    }\r\n    return false\r\n  },\r\n  /**\r\n   * @desc Find the last descendant node that is focusable.\r\n   * @param {HTMLElement} element\r\n   *          DOM node for which to find the last focusable descendant.\r\n   * @returns {Boolean}\r\n   *  true if a focusable element is found and focus is set.\r\n   */\r\n  focusLastDescendant(element: HTMLElement): boolean {\r\n    for (let i = element.childNodes.length - 1; i >= 0; i--) {\r\n      const child = element.childNodes[i] as HTMLElement\r\n      if (attemptFocus(child) || this.focusLastDescendant(child)) {\r\n        return true\r\n      }\r\n    }\r\n    return false\r\n  },\r\n}\r\n\r\nexport default Utils\r\n"],"names":[],"mappings":"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"}