getRole.mjs 5.63 KB
// https://w3c.github.io/html-aria/#document-conformance-requirements-for-use-of-aria-attributes-in-html

/**
 * Safe Element.localName for all supported environments
 * @param element
 */
export function getLocalName(element) {
  var _element$localName;

  return (// eslint-disable-next-line no-restricted-properties -- actual guard for environments without localName
    (_element$localName = element.localName) !== null && _element$localName !== void 0 ? _element$localName : // eslint-disable-next-line no-restricted-properties -- required for the fallback
    element.tagName.toLowerCase()
  );
}
var localNameToRoleMappings = {
  article: "article",
  aside: "complementary",
  button: "button",
  datalist: "listbox",
  dd: "definition",
  details: "group",
  dialog: "dialog",
  dt: "term",
  fieldset: "group",
  figure: "figure",
  // WARNING: Only with an accessible name
  form: "form",
  footer: "contentinfo",
  h1: "heading",
  h2: "heading",
  h3: "heading",
  h4: "heading",
  h5: "heading",
  h6: "heading",
  header: "banner",
  hr: "separator",
  html: "document",
  legend: "legend",
  li: "listitem",
  math: "math",
  main: "main",
  menu: "list",
  nav: "navigation",
  ol: "list",
  optgroup: "group",
  // WARNING: Only in certain context
  option: "option",
  output: "status",
  progress: "progressbar",
  // WARNING: Only with an accessible name
  section: "region",
  summary: "button",
  table: "table",
  tbody: "rowgroup",
  textarea: "textbox",
  tfoot: "rowgroup",
  // WARNING: Only in certain context
  td: "cell",
  th: "columnheader",
  thead: "rowgroup",
  tr: "row",
  ul: "list"
};
var prohibitedAttributes = {
  caption: new Set(["aria-label", "aria-labelledby"]),
  code: new Set(["aria-label", "aria-labelledby"]),
  deletion: new Set(["aria-label", "aria-labelledby"]),
  emphasis: new Set(["aria-label", "aria-labelledby"]),
  generic: new Set(["aria-label", "aria-labelledby", "aria-roledescription"]),
  insertion: new Set(["aria-label", "aria-labelledby"]),
  paragraph: new Set(["aria-label", "aria-labelledby"]),
  presentation: new Set(["aria-label", "aria-labelledby"]),
  strong: new Set(["aria-label", "aria-labelledby"]),
  subscript: new Set(["aria-label", "aria-labelledby"]),
  superscript: new Set(["aria-label", "aria-labelledby"])
};
/**
 *
 * @param element
 * @param role The role used for this element. This is specified to control whether you want to use the implicit or explicit role.
 */

function hasGlobalAriaAttributes(element, role) {
  // https://rawgit.com/w3c/aria/stable/#global_states
  // commented attributes are deprecated
  return ["aria-atomic", "aria-busy", "aria-controls", "aria-current", "aria-describedby", "aria-details", // "disabled",
  "aria-dropeffect", // "errormessage",
  "aria-flowto", "aria-grabbed", // "haspopup",
  "aria-hidden", // "invalid",
  "aria-keyshortcuts", "aria-label", "aria-labelledby", "aria-live", "aria-owns", "aria-relevant", "aria-roledescription"].some(function (attributeName) {
    var _prohibitedAttributes;

    return element.hasAttribute(attributeName) && !((_prohibitedAttributes = prohibitedAttributes[role]) !== null && _prohibitedAttributes !== void 0 && _prohibitedAttributes.has(attributeName));
  });
}

function ignorePresentationalRole(element, implicitRole) {
  // https://rawgit.com/w3c/aria/stable/#conflict_resolution_presentation_none
  return hasGlobalAriaAttributes(element, implicitRole);
}

export default function getRole(element) {
  var explicitRole = getExplicitRole(element);

  if (explicitRole === null || explicitRole === "presentation") {
    var implicitRole = getImplicitRole(element);

    if (explicitRole !== "presentation" || ignorePresentationalRole(element, implicitRole || "")) {
      return implicitRole;
    }
  }

  return explicitRole;
}

function getImplicitRole(element) {
  var mappedByTag = localNameToRoleMappings[getLocalName(element)];

  if (mappedByTag !== undefined) {
    return mappedByTag;
  }

  switch (getLocalName(element)) {
    case "a":
    case "area":
    case "link":
      if (element.hasAttribute("href")) {
        return "link";
      }

      break;

    case "img":
      if (element.getAttribute("alt") === "" && !ignorePresentationalRole(element, "img")) {
        return "presentation";
      }

      return "img";

    case "input":
      {
        var _ref = element,
            type = _ref.type;

        switch (type) {
          case "button":
          case "image":
          case "reset":
          case "submit":
            return "button";

          case "checkbox":
          case "radio":
            return type;

          case "range":
            return "slider";

          case "email":
          case "tel":
          case "text":
          case "url":
            if (element.hasAttribute("list")) {
              return "combobox";
            }

            return "textbox";

          case "search":
            if (element.hasAttribute("list")) {
              return "combobox";
            }

            return "searchbox";

          case "number":
            return "spinbutton";

          default:
            return null;
        }
      }

    case "select":
      if (element.hasAttribute("multiple") || element.size > 1) {
        return "listbox";
      }

      return "combobox";
  }

  return null;
}

function getExplicitRole(element) {
  var role = element.getAttribute("role");

  if (role !== null) {
    var explicitRole = role.trim().split(" ")[0]; // String.prototype.split(sep, limit) will always return an array with at least one member
    // as long as limit is either undefined or > 0

    if (explicitRole.length > 0) {
      return explicitRole;
    }
  }

  return null;
}
//# sourceMappingURL=getRole.mjs.map