{"version":3,"file":"aria.mjs","sources":["../../../../packages/utils/aria.ts"],"sourcesContent":["import type { Nullable } from '@element-plus/utils/types'\nexport const EVENT_CODE = {\n  tab: 'Tab',\n  enter: 'Enter',\n  space: 'Space',\n  left: 'ArrowLeft', // 37\n  up: 'ArrowUp', // 38\n  right: 'ArrowRight', // 39\n  down: 'ArrowDown', // 40\n  esc: 'Escape',\n  delete: 'Delete',\n  backspace: 'Backspace',\n}\n\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])`\n\n/**\n * Determine if the testing element is visible on screen no matter if its on the viewport or not\n */\nexport const isVisible = (element: HTMLElement) => {\n  if (process.env.NODE_ENV === 'test') return true\n  const computed = getComputedStyle(element)\n  // element.offsetParent won't work on fix positioned\n  // WARNING: potential issue here, going to need some expert advices on this issue\n  return computed.position === 'fixed' ? false : element.offsetParent !== null\n}\n\nexport const obtainAllFocusableElements = (\n  element: HTMLElement\n): HTMLElement[] => {\n  return Array.from(\n    element.querySelectorAll<HTMLElement>(FOCUSABLE_ELEMENT_SELECTORS)\n  ).filter((item: HTMLElement) => isFocusable(item) && isVisible(item))\n}\n\n/**\n * @desc Determine if target element is focusable\n * @param element {HTMLElement}\n * @returns {Boolean} true if it is focusable\n */\nexport const isFocusable = (element: HTMLElement): boolean => {\n  if (\n    element.tabIndex > 0 ||\n    (element.tabIndex === 0 && element.getAttribute('tabIndex') !== null)\n  ) {\n    return true\n  }\n  // HTMLButtonElement has disabled\n  if ((element as HTMLButtonElement).disabled) {\n    return false\n  }\n\n  switch (element.nodeName) {\n    case 'A': {\n      // casting current element to Specific HTMLElement in order to be more type precise\n      return (\n        !!(element as HTMLAnchorElement).href &&\n        (element as HTMLAnchorElement).rel !== 'ignore'\n      )\n    }\n    case 'INPUT': {\n      return !(\n        (element as HTMLInputElement).type === 'hidden' ||\n        (element as HTMLInputElement).type === 'file'\n      )\n    }\n    case 'BUTTON':\n    case 'SELECT':\n    case 'TEXTAREA': {\n      return true\n    }\n    default: {\n      return false\n    }\n  }\n}\n\n/**\n * @desc Set Attempt to set focus on the current node.\n * @param element\n *          The node to attempt to focus on.\n * @returns\n *  true if element is focused.\n */\nexport const attemptFocus = (element: HTMLElement): boolean => {\n  if (!isFocusable(element)) {\n    return false\n  }\n  Utils.IgnoreUtilFocusChanges = true\n  // Remove the old try catch block since there will be no error to be thrown\n  element.focus?.()\n  Utils.IgnoreUtilFocusChanges = false\n  return document.activeElement === element\n}\n\n/**\n * Trigger an event\n * mouseenter, mouseleave, mouseover, keyup, change, click, etc.\n * @param  {HTMLElement} elm\n * @param  {String} name\n * @param  {*} opts\n */\nexport const triggerEvent = function (\n  elm: HTMLElement,\n  name: string,\n  ...opts: Array<boolean>\n): HTMLElement {\n  let eventName: string\n\n  if (name.includes('mouse') || name.includes('click')) {\n    eventName = 'MouseEvents'\n  } else if (name.includes('key')) {\n    eventName = 'KeyboardEvent'\n  } else {\n    eventName = 'HTMLEvents'\n  }\n  const evt = document.createEvent(eventName)\n\n  evt.initEvent(name, ...opts)\n  elm.dispatchEvent(evt)\n  return elm\n}\n\nexport const isLeaf = (el: HTMLElement) => !el.getAttribute('aria-owns')\n\nexport const getSibling = (\n  el: HTMLElement,\n  distance: number,\n  elClass: string\n): Nullable<Element> => {\n  const { parentNode } = el\n  if (!parentNode) return null\n  const siblings = parentNode.querySelectorAll(elClass)\n  const index = Array.prototype.indexOf.call(siblings, el)\n  return siblings[index + distance] || null\n}\n\nexport const focusNode = (el) => {\n  if (!el) return\n  el.focus()\n  !isLeaf(el) && el.click()\n}\n\nconst Utils = {\n  IgnoreUtilFocusChanges: false,\n  /**\n   * @desc Set focus on descendant nodes until the first focusable element is\n   *       found.\n   * @param {HTMLElement} element\n   *          DOM node for which to find the first focusable descendant.\n   * @returns {Boolean}\n   *  true if a focusable element is found and focus is set.\n   */\n  focusFirstDescendant(element: HTMLElement): boolean {\n    for (let i = 0; i < element.childNodes.length; i++) {\n      const child = element.childNodes[i] as HTMLElement\n      if (attemptFocus(child) || this.focusFirstDescendant(child)) {\n        return true\n      }\n    }\n    return false\n  },\n  /**\n   * @desc Find the last descendant node that is focusable.\n   * @param {HTMLElement} element\n   *          DOM node for which to find the last focusable descendant.\n   * @returns {Boolean}\n   *  true if a focusable element is found and focus is set.\n   */\n  focusLastDescendant(element: HTMLElement): boolean {\n    for (let i = element.childNodes.length - 1; i >= 0; i--) {\n      const child = element.childNodes[i] as HTMLElement\n      if (attemptFocus(child) || this.focusLastDescendant(child)) {\n        return true\n      }\n    }\n    return false\n  },\n}\n\nexport default Utils\n"],"names":[],"mappings":"MACa,aAAa;AAAA,EACxB,KAAK;AAAA,EACL,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,WAAW;AAAA;AAGb,MAAM,8BAA8B;MAKvB,YAAY,CAAC,YAAyB;AACjD,MAAI,QAAQ,IAAI,aAAa;AAAQ,WAAO;AAC5C,QAAM,WAAW,iBAAiB;AAGlC,SAAO,SAAS,aAAa,UAAU,QAAQ,QAAQ,iBAAiB;AAAA;MAG7D,6BAA6B,CACxC,YACkB;AAClB,SAAO,MAAM,KACX,QAAQ,iBAA8B,8BACtC,OAAO,CAAC,SAAsB,YAAY,SAAS,UAAU;AAAA;MAQpD,cAAc,CAAC,YAAkC;AAC5D,MACE,QAAQ,WAAW,KAClB,QAAQ,aAAa,KAAK,QAAQ,aAAa,gBAAgB,MAChE;AACA,WAAO;AAAA;AAGT,MAAK,QAA8B,UAAU;AAC3C,WAAO;AAAA;AAGT,UAAQ,QAAQ;AAAA,SACT,KAAK;AAER,aACE,CAAC,CAAE,QAA8B,QAChC,QAA8B,QAAQ;AAAA;AAAA,SAGtC,SAAS;AACZ,aAAO,UACyB,SAAS,YACtC,QAA6B,SAAS;AAAA;AAAA,SAGtC;AAAA,SACA;AAAA,SACA,YAAY;AACf,aAAO;AAAA;AAAA,aAEA;AACP,aAAO;AAAA;AAAA;AAAA;MAYA,eAAe,CAAC,YAAkC;AApF/D;AAqFE,MAAI,CAAC,YAAY,UAAU;AACzB,WAAO;AAAA;AAET,QAAM,yBAAyB;AAE/B,gBAAQ,UAAR;AACA,QAAM,yBAAyB;AAC/B,SAAO,SAAS,kBAAkB;AAAA;MAUvB,eAAe,SAC1B,KACA,SACG,MACU;AACb,MAAI;AAEJ,MAAI,KAAK,SAAS,YAAY,KAAK,SAAS,UAAU;AACpD,gBAAY;AAAA,aACH,KAAK,SAAS,QAAQ;AAC/B,gBAAY;AAAA,SACP;AACL,gBAAY;AAAA;AAEd,QAAM,MAAM,SAAS,YAAY;AAEjC,MAAI,UAAU,MAAM,GAAG;AACvB,MAAI,cAAc;AAClB,SAAO;AAAA;MAGI,SAAS,CAAC,OAAoB,CAAC,GAAG,aAAa;MAE/C,aAAa,CACxB,IACA,UACA,YACsB;AACtB,QAAM,EAAE,eAAe;AACvB,MAAI,CAAC;AAAY,WAAO;AACxB,QAAM,WAAW,WAAW,iBAAiB;AAC7C,QAAM,QAAQ,MAAM,UAAU,QAAQ,KAAK,UAAU;AACrD,SAAO,SAAS,QAAQ,aAAa;AAAA;MAG1B,YAAY,CAAC,OAAO;AAC/B,MAAI,CAAC;AAAI;AACT,KAAG;AACH,GAAC,OAAO,OAAO,GAAG;AAAA;MAGd,QAAQ;AAAA,EACZ,wBAAwB;AAAA,EASxB,qBAAqB,SAA+B;AAClD,aAAS,IAAI,GAAG,IAAI,QAAQ,WAAW,QAAQ,KAAK;AAClD,YAAM,QAAQ,QAAQ,WAAW;AACjC,UAAI,aAAa,UAAU,KAAK,qBAAqB,QAAQ;AAC3D,eAAO;AAAA;AAAA;AAGX,WAAO;AAAA;AAAA,EAST,oBAAoB,SAA+B;AACjD,aAAS,IAAI,QAAQ,WAAW,SAAS,GAAG,KAAK,GAAG,KAAK;AACvD,YAAM,QAAQ,QAAQ,WAAW;AACjC,UAAI,aAAa,UAAU,KAAK,oBAAoB,QAAQ;AAC1D,eAAO;AAAA;AAAA;AAGX,WAAO;AAAA;AAAA;;;;"}