aria.mjs 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. 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])`;
  2. const isHTMLElement = (e) => {
  3. if (typeof Element === "undefined")
  4. return false;
  5. return e instanceof Element;
  6. };
  7. const isVisible = (element) => {
  8. if (process.env.NODE_ENV === "test")
  9. return true;
  10. const computed = getComputedStyle(element);
  11. return computed.position === "fixed" ? false : element.offsetParent !== null;
  12. };
  13. const obtainAllFocusableElements = (element) => {
  14. return Array.from(
  15. element.querySelectorAll(FOCUSABLE_ELEMENT_SELECTORS)
  16. ).filter((item) => isFocusable(item) && isVisible(item));
  17. };
  18. const isFocusable = (element) => {
  19. if (element.tabIndex > 0 || element.tabIndex === 0 && element.getAttribute("tabIndex") !== null) {
  20. return true;
  21. }
  22. if (element.tabIndex < 0 || element.hasAttribute("disabled") || element.getAttribute("aria-disabled") === "true") {
  23. return false;
  24. }
  25. switch (element.nodeName) {
  26. case "A": {
  27. return !!element.href && element.rel !== "ignore";
  28. }
  29. case "INPUT": {
  30. return !(element.type === "hidden" || element.type === "file");
  31. }
  32. case "BUTTON":
  33. case "SELECT":
  34. case "TEXTAREA": {
  35. return true;
  36. }
  37. default: {
  38. return false;
  39. }
  40. }
  41. };
  42. const triggerEvent = function(elm, name, ...opts) {
  43. let eventName;
  44. if (name.includes("mouse") || name.includes("click")) {
  45. eventName = "MouseEvents";
  46. } else if (name.includes("key")) {
  47. eventName = "KeyboardEvent";
  48. } else {
  49. eventName = "HTMLEvents";
  50. }
  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)
  60. return null;
  61. const siblings = parentNode.querySelectorAll(elClass);
  62. const index = Array.prototype.indexOf.call(siblings, el);
  63. return siblings[index + distance] || null;
  64. };
  65. const focusElement = (el, options) => {
  66. if (!el || !el.focus)
  67. return;
  68. let cleanup = false;
  69. if (isHTMLElement(el) && !isFocusable(el) && !el.getAttribute("tabindex")) {
  70. el.setAttribute("tabindex", "-1");
  71. cleanup = true;
  72. }
  73. el.focus(options);
  74. if (isHTMLElement(el) && cleanup) {
  75. el.removeAttribute("tabindex");
  76. }
  77. };
  78. const focusNode = (el) => {
  79. if (!el)
  80. return;
  81. focusElement(el);
  82. !isLeaf(el) && el.click();
  83. };
  84. export { focusElement, focusNode, getSibling, isFocusable, isLeaf, isVisible, obtainAllFocusableElements, triggerEvent };
  85. //# sourceMappingURL=aria.mjs.map