aria.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  2. //#region ../../packages/utils/dom/aria.ts
  3. const 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])`;
  4. const isShadowRoot = (e) => {
  5. if (typeof ShadowRoot === "undefined") return false;
  6. return e instanceof ShadowRoot;
  7. };
  8. const isHTMLElement = (e) => {
  9. if (typeof Element === "undefined") return false;
  10. return e instanceof Element;
  11. };
  12. /**
  13. * Determine if the testing element is visible on screen no matter if its on the viewport or not
  14. */
  15. const isVisible = (element) => {
  16. if (process.env.NODE_ENV === "test") return true;
  17. return getComputedStyle(element).position === "fixed" ? false : element.offsetParent !== null;
  18. };
  19. const obtainAllFocusableElements = (element) => {
  20. return Array.from(element.querySelectorAll(FOCUSABLE_ELEMENT_SELECTORS)).filter((item) => isFocusable(item) && isVisible(item));
  21. };
  22. /**
  23. * @desc Determine if target element is focusable
  24. * @param element {HTMLElement}
  25. * @returns {Boolean} true if it is focusable
  26. */
  27. const isFocusable = (element) => {
  28. if (element.tabIndex > 0 || element.tabIndex === 0 && element.getAttribute("tabIndex") !== null) return true;
  29. if (element.tabIndex < 0 || element.hasAttribute("disabled") || element.getAttribute("aria-disabled") === "true") return false;
  30. switch (element.nodeName) {
  31. case "A": return !!element.href && element.rel !== "ignore";
  32. case "INPUT": return !(element.type === "hidden" || element.type === "file");
  33. case "BUTTON":
  34. case "SELECT":
  35. case "TEXTAREA": return true;
  36. default: return false;
  37. }
  38. };
  39. /**
  40. * Trigger an event
  41. * mouseenter, mouseleave, mouseover, keyup, change, click, etc.
  42. * @param {HTMLElement} elm
  43. * @param {String} name
  44. * @param {*} opts
  45. */
  46. const triggerEvent = function(elm, name, ...opts) {
  47. let eventName;
  48. if (name.includes("mouse") || name.includes("click")) eventName = "MouseEvents";
  49. else if (name.includes("key")) eventName = "KeyboardEvent";
  50. else eventName = "HTMLEvents";
  51. const evt = document.createEvent(eventName);
  52. evt.initEvent(name, ...opts);
  53. elm.dispatchEvent(evt);
  54. return elm;
  55. };
  56. const isLeaf = (el) => !el.getAttribute("aria-owns");
  57. const getSibling = (el, distance, elClass) => {
  58. const { parentNode } = el;
  59. if (!parentNode) return null;
  60. const siblings = parentNode.querySelectorAll(elClass);
  61. return siblings[Array.prototype.indexOf.call(siblings, el) + distance] || null;
  62. };
  63. const focusElement = (el, options) => {
  64. if (!el || !el.focus) return;
  65. let cleanup = false;
  66. if (isHTMLElement(el) && !isFocusable(el) && !el.getAttribute("tabindex")) {
  67. el.setAttribute("tabindex", "-1");
  68. cleanup = true;
  69. }
  70. el.focus(options);
  71. if (isHTMLElement(el) && cleanup) el.removeAttribute("tabindex");
  72. };
  73. const focusNode = (el) => {
  74. if (!el) return;
  75. focusElement(el);
  76. !isLeaf(el) && el.click();
  77. };
  78. //#endregion
  79. exports.focusElement = focusElement;
  80. exports.focusNode = focusNode;
  81. exports.getSibling = getSibling;
  82. exports.isFocusable = isFocusable;
  83. exports.isLeaf = isLeaf;
  84. exports.isShadowRoot = isShadowRoot;
  85. exports.isVisible = isVisible;
  86. exports.obtainAllFocusableElements = obtainAllFocusableElements;
  87. exports.triggerEvent = triggerEvent;
  88. //# sourceMappingURL=aria.js.map