aria-api

access ARIA information from JavaScript
git clone https://git.ce9e.org/aria-api.git

commit
1c417094f13611e33f6aaa1f75ffd8822ff0422a
parent
5079421d48424eefeabb0b210763fd14fe78f59f
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2024-02-04 15:02
bump version to 0.6.0

Diffstat

M CHANGES.md 13 +++++++++++++
M dist/aria.js 339 +++++++++++++++++++++++++++++++++++++++----------------------
M package.json 2 +-

3 files changed, 230 insertions, 124 deletions


diff --git a/CHANGES.md b/CHANGES.md

@@ -1,3 +1,16 @@
   -1     1 0.6.0 (2024-02-04)
   -1     2 ------------------
   -1     3 
   -1     4 -	getRole
   -1     5 	-	use Web Platform Tests
   -1     6 	-	fix rowheader selectors
   -1     7 	-	fix listitem selectors
   -1     8 	-	fix: directory is an alias for list
   -1     9 	-	never return invalid, abstract, or alias roles
   -1    10 	-	fall back to implicit role if all explicit roles are invalid
   -1    11 -	getName
   -1    12 	-	increase priority of embedded input element
   -1    13 
    1    14 0.5.0 (2023-06-07)
    2    15 ------------------
    3    16 

diff --git a/dist/aria.js b/dist/aria.js

@@ -19,13 +19,13 @@ module.exports = {
   19    19 };
   20    20 
   21    21 },{"./lib/atree.js":2,"./lib/name.js":5,"./lib/query.js":6}],2:[function(require,module,exports){
   22    -1 var attrs = require('./attrs');
   -1    22 const attrs = require('./attrs');
   23    23 
   24    -1 var _getOwner = function(node, owners) {
   -1    24 const _getOwner = function(node, owners) {
   25    25 	if (node.nodeType === node.ELEMENT_NODE && node.id) {
   26    -1 		var selector = '[aria-owns~="' + CSS.escape(node.id) + '"]';
   -1    26 		const selector = '[aria-owns~="' + CSS.escape(node.id) + '"]';
   27    27 		if (owners) {
   28    -1 			for (var owner of owners) {
   -1    28 			for (const owner of owners) {
   29    29 				if (owner.matches(selector)) {
   30    30 					return owner;
   31    31 				}
@@ -36,12 +36,12 @@ var _getOwner = function(node, owners) {
   36    36 	}
   37    37 };
   38    38 
   39    -1 var _getParentNode = function(node, owners) {
   -1    39 const _getParentNode = function(node, owners) {
   40    40 	return _getOwner(node, owners) || node.parentNode;
   41    41 };
   42    42 
   43    -1 var detectLoop = function(node, owners) {
   44    -1 	var seen = [node];
   -1    43 const detectLoop = function(node, owners) {
   -1    44 	const seen = [node];
   45    45 	while ((node = _getParentNode(node, owners))) {
   46    46 		if (seen.includes(node)) {
   47    47 			return true;
@@ -50,35 +50,35 @@ var detectLoop = function(node, owners) {
   50    50 	}
   51    51 };
   52    52 
   53    -1 var getOwner = function(node, owners) {
   54    -1 	var owner = _getOwner(node, owners);
   -1    53 const getOwner = function(node, owners) {
   -1    54 	const owner = _getOwner(node, owners);
   55    55 	if (owner && !detectLoop(node, owners)) {
   56    56 		return owner;
   57    57 	}
   58    58 };
   59    59 
   60    -1 var getParentNode = function(node, owners) {
   -1    60 const getParentNode = function(node, owners) {
   61    61 	return getOwner(node, owners) || node.parentNode;
   62    62 };
   63    63 
   64    -1 var isHidden = function(node) {
   -1    64 const isHidden = function(node) {
   65    65 	return node.nodeType === node.ELEMENT_NODE && attrs.getAttribute(node, 'hidden');
   66    66 };
   67    67 
   68    -1 var getChildNodes = function(node, owners) {
   69    -1 	var childNodes = [];
   -1    68 const getChildNodes = function(node, owners) {
   -1    69 	const childNodes = [];
   70    70 
   71    -1 	for (var i = 0; i < node.childNodes.length; i++) {
   72    -1 		var child = node.childNodes[i];
   -1    71 	for (let i = 0; i < node.childNodes.length; i++) {
   -1    72 		const child = node.childNodes[i];
   73    73 		if (!getOwner(child, owners) && !isHidden(child)) {
   74    74 			childNodes.push(child);
   75    75 		}
   76    76 	}
   77    77 
   78    78 	if (node.nodeType === node.ELEMENT_NODE) {
   79    -1 		var owns = attrs.getAttribute(node, 'owns') || [];
   80    -1 		for (var i = 0; i < owns.length; i++) {
   81    -1 			var child = document.getElementById(owns[i]);
   -1    79 		const owns = attrs.getAttribute(node, 'owns') || [];
   -1    80 		for (let i = 0; i < owns.length; i++) {
   -1    81 			const child = document.getElementById(owns[i]);
   82    82 			// double check with getOwner for consistency
   83    83 			if (child && getOwner(child, owners) === node && !isHidden(child)) {
   84    84 				childNodes.push(child);
@@ -89,18 +89,18 @@ var getChildNodes = function(node, owners) {
   89    89 	return childNodes;
   90    90 };
   91    91 
   92    -1 var walk = function(root, fn) {
   93    -1 	var owners = document.querySelectorAll('[aria-owns]');
   94    -1 	var queue = [root];
   -1    92 const walk = function(root, fn) {
   -1    93 	const owners = document.querySelectorAll('[aria-owns]');
   -1    94 	let queue = [root];
   95    95 	while (queue.length) {
   96    -1 		var item = queue.shift();
   -1    96 		const item = queue.shift();
   97    97 		fn(item);
   98    98 		queue = getChildNodes(item, owners).concat(queue);
   99    99 	}
  100   100 };
  101   101 
  102    -1 var searchUp = function(node, test) {
  103    -1 	var candidate = getParentNode(node);
   -1   102 const searchUp = function(node, test) {
   -1   103 	const candidate = getParentNode(node);
  104   104 	if (candidate) {
  105   105 		if (test(candidate)) {
  106   106 			return candidate;
@@ -118,44 +118,59 @@ module.exports = {
  118   118 };
  119   119 
  120   120 },{"./attrs":3}],3:[function(require,module,exports){
  121    -1 var constants = require('./constants.js');
   -1   121 const constants = require('./constants.js');
   -1   122 
   -1   123 var unique = function(arr) {
   -1   124 	return arr.filter((a, i) => arr.indexOf(a) === i);
   -1   125 };
   -1   126 
   -1   127 var flatten = function(arr) {
   -1   128 	return [].concat.apply([], arr);
   -1   129 };
   -1   130 
   -1   131 var normalizeRoles = function(roles, includeAbstract) {
   -1   132 	return unique(roles
   -1   133 		.map(r => constants.aliases[r] || r)
   -1   134 		.filter(r => constants.roles[r])
   -1   135 		.filter(r => includeAbstract || !constants.roles[r].abstract)
   -1   136 	);
   -1   137 };
  122   138 
  123   139 // candidates can be passed for performance optimization
  124    -1 var getRole = function(el, candidates) {
  125    -1 	if (el.hasAttribute('role')) {
  126    -1 		var roles = el.getAttribute('role').toLowerCase().split(/\s+/);
  127    -1 		if (roles.length > 1 && candidates) {
  128    -1 			return [roles, candidates];
  129    -1 		}
  130    -1 		for (var role of roles) {
   -1   140 const getRole = function(el, candidates) {
   -1   141 	// TODO: filter out any invalid roles (e.g. name or context required)
   -1   142 	const roles = normalizeRoles(
   -1   143 		(el.getAttribute('role') || '').toLowerCase().split(/\s+/)
   -1   144 	);
   -1   145 
   -1   146 	if (roles.length > 1 && candidates) {
   -1   147 		return [roles, candidates];
   -1   148 	} else if (roles.length) {
   -1   149 		for (const role of roles) {
  131   150 			if (!candidates || candidates.includes(role)) {
  132   151 				return role;
  133   152 			}
  134   153 		}
  135   154 	} else {
  136    -1 		var roles = candidates ? candidates : Object.keys(constants.roles);
  137    -1 		for (var role of roles) {
  138    -1 			var r = constants.roles[role];
  139    -1 			if (r) {
  140    -1 				var selector = (r.selectors || []).join(',');
  141    -1 				if (selector && el.matches(selector)) {
  142    -1 					return role;
  143    -1 				}
   -1   155 		for (const role of (candidates || Object.keys(constants.roles))) {
   -1   156 			const r = constants.roles[role];
   -1   157 			if (!r.abstract && r.selectors && el.matches(r.selectors.join(','))) {
   -1   158 				return role;
  144   159 			}
  145   160 		}
  146   161 	}
  147   162 };
  148   163 
  149    -1 var hasRole = function(el, roles) {
  150    -1 	var candidates = [].concat.apply([], roles.map(role => {
  151    -1 		return (constants.roles[role] || {}).subRoles || [role];
  152    -1 	}));
  153    -1 	return !!getRole(el, candidates);
   -1   164 const hasRole = function(el, roles) {
   -1   165 	const subRoles = normalizeRoles(roles, true).map(role => {
   -1   166 		return constants.roles[role].subRoles || [role];
   -1   167 	});
   -1   168 	return !!getRole(el, unique(flatten(subRoles)));
  154   169 };
  155   170 
  156    -1 var getAttribute = function(el, key) {
   -1   171 const getAttribute = function(el, key) {
  157   172 	if (constants.attributeStrongMapping.hasOwnProperty(key)) {
  158    -1 		var value = el[constants.attributeStrongMapping[key]];
   -1   173 		const value = el[constants.attributeStrongMapping[key]];
  159   174 		if (value) {
  160   175 			return value;
  161   176 		}
@@ -172,14 +187,14 @@ var getAttribute = function(el, key) {
  172   187 		if (el.matches('details:not([open]) > :not(summary)')) {
  173   188 			return true;
  174   189 		}
  175    -1 		var style = window.getComputedStyle(el);
   -1   190 		const style = window.getComputedStyle(el);
  176   191 		if (style.display === 'none' || style.visibility === 'hidden') {
  177   192 			return true;
  178   193 		}
  179   194 	}
  180   195 
  181    -1 	var type = constants.attributes[key];
  182    -1 	var raw = el.getAttribute('aria-' + key);
   -1   196 	const type = constants.attributes[key];
   -1   197 	const raw = el.getAttribute('aria-' + key);
  183   198 
  184   199 	if (raw) {
  185   200 		if (type === 'bool') {
@@ -208,7 +223,7 @@ var getAttribute = function(el, key) {
  208   223 	// list -> aria-controls
  209   224 
  210   225 	if (key === 'level') {
  211    -1 		for (var i = 1; i <= 6; i++) {
   -1   226 		for (let i = 1; i <= 6; i++) {
  212   227 			if (el.tagName.toLowerCase() === 'h' + i) {
  213   228 				return i;
  214   229 			}
@@ -218,8 +233,8 @@ var getAttribute = function(el, key) {
  218   233 	}
  219   234 
  220   235 	if (key in constants.attrsWithDefaults) {
  221    -1 		var role = getRole(el);
  222    -1 		var defaults = (constants.roles[role] || {}).defaults;
   -1   236 		const role = getRole(el);
   -1   237 		const defaults = constants.roles[role].defaults;
  223   238 		if (defaults && defaults.hasOwnProperty(key)) {
  224   239 			return defaults[key];
  225   240 		}
@@ -306,7 +321,7 @@ exports.attributeWeakMapping = {
  306   321 };
  307   322 
  308   323 // https://www.w3.org/TR/html/dom.html#sectioning-content-2
  309    -1 var scoped = ['article *', 'aside *', 'nav *', 'section *'].join(',');
   -1   324 const scoped = ['article *', 'aside *', 'nav *', 'section *'].join(',');
  310   325 
  311   326 // https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings
  312   327 // https://www.w3.org/TR/wai-aria/roles
@@ -318,6 +333,8 @@ exports.roles = {
  318   333 			'atomic': true,
  319   334 		},
  320   335 	},
   -1   336 	alertdialog: {},
   -1   337 	application: {},
  321   338 	article: {
  322   339 		selectors: ['article'],
  323   340 	},
@@ -342,7 +359,7 @@ exports.roles = {
  342   359 		selectors: ['caption', 'figcaption'],
  343   360 	},
  344   361 	cell: {
  345    -1 		selectors: ['td', 'th:not([scope])'],
   -1   362 		selectors: ['td', 'td ~ th:not([scope])'],
  346   363 		childRoles: ['columnheader', 'gridcell', 'rowheader'],
  347   364 		nameFromContents: true,
  348   365 	},
@@ -379,6 +396,7 @@ exports.roles = {
  379   396 		},
  380   397 	},
  381   398 	command: {
   -1   399 		abstract: true,
  382   400 		childRoles: ['button', 'link', 'menuitem'],
  383   401 	},
  384   402 	complementary: {
@@ -390,6 +408,7 @@ exports.roles = {
  390   408 		],
  391   409 	},
  392   410 	composite: {
   -1   411 		abstract: true,
  393   412 		childRoles: ['grid', 'select', 'spinbutton', 'tablist'],
  394   413 	},
  395   414 	contentinfo: {
@@ -405,24 +424,59 @@ exports.roles = {
  405   424 		selectors: ['dialog'],
  406   425 		childRoles: ['alertdialog'],
  407   426 	},
   -1   427 	'doc-abstract': {},
   -1   428 	'doc-acknowledgments': {},
   -1   429 	'doc-afterword': {},
   -1   430 	'doc-appendix': {},
  408   431 	'doc-backlink': {
  409   432 		nameFromContents: true,
  410   433 	},
   -1   434 	'doc-biblioentry': {},
   -1   435 	'doc-bibliography': {},
  411   436 	'doc-biblioref': {
  412   437 		nameFromContents: true,
  413   438 	},
   -1   439 	'doc-chapter': {},
   -1   440 	'doc-colophon': {},
   -1   441 	'doc-conclusion': {},
   -1   442 	'doc-cover': {},
   -1   443 	'doc-credit': {},
   -1   444 	'doc-credits': {},
   -1   445 	'doc-dedication': {},
   -1   446 	'doc-endnote': {},
   -1   447 	'doc-endnotes': {},
   -1   448 	'doc-epilogue': {},
   -1   449 	'doc-epigraph': {},
   -1   450 	'doc-errata': {},
   -1   451 	'doc-example': {},
   -1   452 	'doc-footnote': {},
   -1   453 	'doc-foreword': {},
   -1   454 	'doc-glossary': {},
  414   455 	'doc-glossref': {
  415   456 		nameFromContents: true,
  416   457 	},
   -1   458 	'doc-index': {},
   -1   459 	'doc-introduction': {},
  417   460 	'doc-noteref': {
  418   461 		nameFromContents: true,
  419   462 	},
   -1   463 	'doc-notice': {},
  420   464 	'doc-pagebreak': {
  421   465 		nameFromContents: true,
  422   466 	},
   -1   467 	'doc-pagefooter': {},
   -1   468 	'doc-pageheader': {},
   -1   469 	'doc-pagelist': {},
   -1   470 	'doc-part': {},
   -1   471 	'doc-preface': {},
   -1   472 	'doc-prologue': {},
   -1   473 	'doc-pullquote': {},
   -1   474 	'doc-qna': {},
  423   475 	'doc-subtitle': {
  424   476 		nameFromContents: true,
  425   477 	},
   -1   478 	'doc-tip': {},
   -1   479 	'doc-toc': {},
  426   480 	document: {
  427   481 		selectors: ['html'],
  428   482 		childRoles: ['article', 'graphics-document'],
@@ -430,6 +484,7 @@ exports.roles = {
  430   484 	emphasis: {
  431   485 		selectors: ['em'],
  432   486 	},
   -1   487 	feed: {},
  433   488 	figure: {
  434   489 		selectors: ['figure'],
  435   490 		childRoles: ['doc-example'],
@@ -438,11 +493,34 @@ exports.roles = {
  438   493 		selectors: ['form[aria-label]', 'form[aria-labelledby]', 'form[title]'],
  439   494 	},
  440   495 	generic: {
  441    -1 		// too many selectors to list
   -1   496 		selectors: [
   -1   497 			'a:not([href])',
   -1   498 			'area:not([href])',
   -1   499 			`aside:not(${scoped}):not([aria-label]):not([aria-labelledby]):not([title])`,
   -1   500 			'b',
   -1   501 			'bdi',
   -1   502 			'bdo',
   -1   503 			'body',
   -1   504 			'data',
   -1   505 			'div',
   -1   506 			// footer scoped
   -1   507 			// header scoped
   -1   508 			'i',
   -1   509 			'li:not(ul > li):not(ol > li)',
   -1   510 			'pre',
   -1   511 			'q',
   -1   512 			'samp',
   -1   513 			'section:not([aria-label]):not([aria-labelledby]):not([title])',
   -1   514 			'small',
   -1   515 			'span',
   -1   516 			'u',
   -1   517 		],
  442   518 	},
  443   519 	'graphics-document': {
  444   520 		selectors: ['svg'],
  445   521 	},
   -1   522 	'graphics-object': {},
   -1   523 	'graphics-symbol': {},
  446   524 	grid: {
  447   525 		childRoles: ['treegrid'],
  448   526 	},
@@ -473,6 +551,7 @@ exports.roles = {
  473   551 		childRoles: ['doc-cover'],
  474   552 	},
  475   553 	input: {
   -1   554 		abstract: true,
  476   555 		childRoles: [
  477   556 			'checkbox',
  478   557 			'combobox',
@@ -487,6 +566,7 @@ exports.roles = {
  487   566 		selectors: ['ins'],
  488   567 	},
  489   568 	landmark: {
   -1   569 		abstract: true,
  490   570 		childRoles: [
  491   571 			'banner',
  492   572 			'complementary',
@@ -521,7 +601,7 @@ exports.roles = {
  521   601 	},
  522   602 	list: {
  523   603 		selectors: ['dl', 'ol', 'ul', 'menu'],
  524    -1 		childRoles: ['directory', 'feed'],
   -1   604 		childRoles: ['feed'],
  525   605 	},
  526   606 	listbox: {
  527   607 		selectors: [
@@ -534,7 +614,7 @@ exports.roles = {
  534   614 		},
  535   615 	},
  536   616 	listitem: {
  537    -1 		selectors: ['li'],
   -1   617 		selectors: ['ol > li', 'ul > li'],
  538   618 		childRoles: ['doc-biblioentry', 'doc-endnote', 'treeitem'],
  539   619 	},
  540   620 	log: {
@@ -545,6 +625,7 @@ exports.roles = {
  545   625 	main: {
  546   626 		selectors: ['main'],
  547   627 	},
   -1   628 	marquee: {},
  548   629 	math: {
  549   630 		selectors: ['math'],
  550   631 	},
@@ -587,6 +668,9 @@ exports.roles = {
  587   668 		selectors: ['nav'],
  588   669 		childRoles: ['doc-index', 'doc-pagelist', 'doc-toc'],
  589   670 	},
   -1   671 	none: {
   -1   672 		selectors: ['img[alt=""]'],
   -1   673 	},
  590   674 	note: {
  591   675 		childRoles: ['doc-notice', 'doc-tip'],
  592   676 	},
@@ -601,9 +685,6 @@ exports.roles = {
  601   685 	paragraph: {
  602   686 		selectors: ['p'],
  603   687 	},
  604    -1 	presentation: {
  605    -1 		selectors: ['img[alt=""]'],
  606    -1 	},
  607   688 	progressbar: {
  608   689 		selectors: ['progress'],
  609   690 		defaults: {
@@ -619,13 +700,16 @@ exports.roles = {
  619   700 			'checked': 'false',
  620   701 		},
  621   702 	},
   -1   703 	radiogroup: {},
  622   704 	range: {
   -1   705 		abstract: true,
  623   706 		childRoles: ['meter', 'progressbar', 'scrollbar', 'slider', 'spinbutton'],
  624   707 	},
  625   708 	region: {
  626   709 		selectors: ['section[aria-label]', 'section[aria-labelledby]', 'section[title]'],
  627   710 	},
  628   711 	roletype: {
   -1   712 		abstract: true,
  629   713 		childRoles: ['structure', 'widget', 'window'],
  630   714 	},
  631   715 	row: {
@@ -636,7 +720,7 @@ exports.roles = {
  636   720 		selectors: ['tbody', 'thead', 'tfoot'],
  637   721 	},
  638   722 	rowheader: {
  639    -1 		selectors: ['th[scope="row"]'],
   -1   723 		selectors: ['th[scope="row"]', 'th:not([scope]):not(td ~ th)'],
  640   724 		nameFromContents: true,
  641   725 	},
  642   726 	scrollbar: {
@@ -653,6 +737,7 @@ exports.roles = {
  653   737 		selectors: ['input[type="search"]:not([list])'],
  654   738 	},
  655   739 	section: {
   -1   740 		abstract: true,
  656   741 		childRoles: [
  657   742 			'alert',
  658   743 			'blockquote',
@@ -696,6 +781,7 @@ exports.roles = {
  696   781 		],
  697   782 	},
  698   783 	sectionhead: {
   -1   784 		abstract: true,
  699   785 		childRoles: [
  700   786 			'columnheader',
  701   787 			'doc-subtitle',
@@ -706,6 +792,7 @@ exports.roles = {
  706   792 		nameFromContents: true,
  707   793 	},
  708   794 	select: {
   -1   795 		abstract: true,
  709   796 		childRoles: ['listbox', 'menu', 'radiogroup', 'tree'],
  710   797 	},
  711   798 	separator: {
@@ -746,12 +833,12 @@ exports.roles = {
  746   833 		selectors: ['strong'],
  747   834 	},
  748   835 	structure: {
   -1   836 		abstract: true,
  749   837 		childRoles: [
  750   838 			'application',
  751   839 			'document',
  752   840 			'none',
  753   841 			'generic',
  754    -1 			'presentation',
  755   842 			'range',
  756   843 			'rowgroup',
  757   844 			'section',
@@ -759,6 +846,7 @@ exports.roles = {
  759   846 			'separator',
  760   847 		],
  761   848 	},
   -1   849 	suggestion: {},
  762   850 	subscript: {
  763   851 		selectors: ['sub'],
  764   852 	},
@@ -786,6 +874,7 @@ exports.roles = {
  786   874 			'orientation': 'horizontal',
  787   875 		},
  788   876 	},
   -1   877 	tabpanel: {},
  789   878 	term: {
  790   879 		selectors: ['dfn', 'dt'],
  791   880 	},
@@ -822,10 +911,12 @@ exports.roles = {
  822   911 			'orientation': 'vertical',
  823   912 		},
  824   913 	},
   -1   914 	treegrid: {},
  825   915 	treeitem: {
  826   916 		nameFromContents: true,
  827   917 	},
  828   918 	widget: {
   -1   919 		abstract: true,
  829   920 		childRoles: [
  830   921 			'command',
  831   922 			'composite',
@@ -839,15 +930,16 @@ exports.roles = {
  839   930 		],
  840   931 	},
  841   932 	window: {
   -1   933 		abstract: true,
  842   934 		childRoles: ['dialog'],
  843   935 	},
  844   936 };
  845   937 
  846    -1 var getSubRoles = function(role) {
  847    -1 	var children = (exports.roles[role] || {}).childRoles || [];
  848    -1 	var descendents = children.map(getSubRoles);
   -1   938 const getSubRoles = function(role) {
   -1   939 	const children = (exports.roles[role]).childRoles || [];
   -1   940 	const descendents = children.map(getSubRoles);
  849   941 
  850    -1 	var result = [role];
   -1   942 	const result = [role];
  851   943 
  852   944 	descendents.forEach(list => {
  853   945 		list.forEach(r => {
@@ -862,18 +954,19 @@ var getSubRoles = function(role) {
  862   954 
  863   955 exports.attrsWithDefaults = [];
  864   956 
  865    -1 for (var role in exports.roles) {
   -1   957 for (const role in exports.roles) {
  866   958 	exports.roles[role].subRoles = getSubRoles(role);
  867    -1 	for (var key in exports.roles[role].defaults) {
   -1   959 	for (const key in exports.roles[role].defaults) {
  868   960 		if (!exports.attrsWithDefaults.includes(key)) {
  869   961 			exports.attrsWithDefaults.push(key);
  870   962 		}
  871   963 	}
  872   964 }
  873    -1 exports.roles['none'] = exports.roles['none'] || {};
  874    -1 exports.roles['none'].subRoles = ['none', 'presentation'];
  875    -1 exports.roles['presentation'] = exports.roles['presentation'] || {};
  876    -1 exports.roles['presentation'].subRoles = ['presentation', 'none'];
   -1   965 
   -1   966 exports.aliases = {
   -1   967 	'presentation': 'none',
   -1   968 	'directory': 'list',
   -1   969 };
  877   970 
  878   971 exports.nameFromDescendant = {
  879   972 	'figure': 'figcaption',
@@ -888,14 +981,14 @@ exports.nameDefaults = {
  888   981 };
  889   982 
  890   983 },{}],5:[function(require,module,exports){
  891    -1 var constants = require('./constants.js');
  892    -1 var atree = require('./atree.js');
  893    -1 var query = require('./query.js');
  894    -1 
  895    -1 var getPseudoContent = function(node, selector) {
  896    -1 	var styles = window.getComputedStyle(node, selector);
  897    -1 	var ret = styles.getPropertyValue('content');
  898    -1 	var inline = styles.display.substr(0, 6) === 'inline';
   -1   984 const constants = require('./constants.js');
   -1   985 const atree = require('./atree.js');
   -1   986 const query = require('./query.js');
   -1   987 
   -1   988 const getPseudoContent = function(node, selector) {
   -1   989 	const styles = window.getComputedStyle(node, selector);
   -1   990 	const ret = styles.getPropertyValue('content');
   -1   991 	const inline = styles.display.substr(0, 6) === 'inline';
  899   992 	if (!ret) {
  900   993 		return '';
  901   994 	}
@@ -910,12 +1003,12 @@ var getPseudoContent = function(node, selector) {
  910  1003 	}
  911  1004 };
  912  1005 
  913    -1 var getContent = function(root, visited) {
  914    -1 	var children = atree.getChildNodes(root);
   -1  1006 const getContent = function(root, visited) {
   -1  1007 	const children = atree.getChildNodes(root);
  915  1008 
  916    -1 	var ret = '';
  917    -1 	for (var i = 0; i < children.length; i++) {
  918    -1 		var node = children[i];
   -1  1009 	let ret = '';
   -1  1010 	for (let i = 0; i < children.length; i++) {
   -1  1011 		const node = children[i];
  919  1012 		if (node.nodeType === node.TEXT_NODE) {
  920  1013 			ret += node.textContent;
  921  1014 		} else if (node.nodeType === node.ELEMENT_NODE) {
@@ -934,13 +1027,15 @@ var getContent = function(root, visited) {
  934  1027 	return ret;
  935  1028 };
  936  1029 
  937    -1 var allowNameFromContent = function(el) {
  938    -1 	var role = query.getRole(el);
  939    -1 	return (constants.roles[role] || {}).nameFromContents;
   -1  1030 const allowNameFromContent = function(el) {
   -1  1031 	const role = query.getRole(el);
   -1  1032 	if (role) {
   -1  1033 		return constants.roles[role].nameFromContents;
   -1  1034 	}
  940  1035 };
  941  1036 
  942    -1 var getName = function(el, recursive, visited, directReference) {
  943    -1 	var ret = '';
   -1  1037 const getName = function(el, recursive, visited, directReference) {
   -1  1038 	let ret = '';
  944  1039 
  945  1040 	visited = visited || [];
  946  1041 	if (visited.includes(el)) {
@@ -956,9 +1051,9 @@ var getName = function(el, recursive, visited, directReference) {
  956  1051 
  957  1052 	// B
  958  1053 	if (!recursive && el.matches('[aria-labelledby]')) {
  959    -1 		var ids = el.getAttribute('aria-labelledby').split(/\s+/);
  960    -1 		var strings = ids.map(id => {
  961    -1 			var label = document.getElementById(id);
   -1  1054 		const ids = el.getAttribute('aria-labelledby').split(/\s+/);
   -1  1055 		const strings = ids.map(id => {
   -1  1056 			const label = document.getElementById(id);
  962  1057 			return label ? getName(label, true, visited, true) : '';
  963  1058 		});
  964  1059 		ret = strings.join(' ');
@@ -969,7 +1064,7 @@ var getName = function(el, recursive, visited, directReference) {
  969  1064 		if (query.matches(el, 'textbox,button')) {
  970  1065 			ret = el.value || el.textContent;
  971  1066 		} else if (query.matches(el, 'combobox,listbox')) {
  972    -1 			var selected = query.querySelector(el, ':selected') || query.querySelector(el, 'option');
   -1  1067 			const selected = query.querySelector(el, ':selected') || query.querySelector(el, 'option');
  973  1068 			if (selected) {
  974  1069 				ret = getName(selected, recursive, visited);
  975  1070 			} else {
@@ -988,7 +1083,7 @@ var getName = function(el, recursive, visited, directReference) {
  988  1083 
  989  1084 	// D
  990  1085 	if (!ret.trim() && !recursive && el.labels) {
  991    -1 		var strings = Array.prototype.map.call(el.labels, label => {
   -1  1086 		const strings = Array.prototype.map.call(el.labels, label => {
  992  1087 			return getName(label, true, visited);
  993  1088 		});
  994  1089 		ret = strings.join(' ');
@@ -1003,9 +1098,9 @@ var getName = function(el, recursive, visited, directReference) {
 1003  1098 		ret = el.title;
 1004  1099 	}
 1005  1100 	if (!ret.trim()) {
 1006    -1 		for (var selector in constants.nameFromDescendant) {
   -1  1101 		for (const selector in constants.nameFromDescendant) {
 1007  1102 			if (el.matches(selector)) {
 1008    -1 				var descendant = el.querySelector(constants.nameFromDescendant[selector]);
   -1  1103 				const descendant = el.querySelector(constants.nameFromDescendant[selector]);
 1009  1104 				if (descendant) {
 1010  1105 					ret = getName(descendant, true, visited);
 1011  1106 				}
@@ -1013,7 +1108,7 @@ var getName = function(el, recursive, visited, directReference) {
 1013  1108 		}
 1014  1109 	}
 1015  1110 	if (!ret.trim() && el.matches('svg *')) {
 1016    -1 		var svgTitle = el.querySelector('title');
   -1  1111 		const svgTitle = el.querySelector('title');
 1017  1112 		if (svgTitle && svgTitle.parentElement === el) {
 1018  1113 			ret = svgTitle.textContent;
 1019  1114 		}
@@ -1030,7 +1125,7 @@ var getName = function(el, recursive, visited, directReference) {
 1030  1125 	}
 1031  1126 
 1032  1127 	if (!ret.trim()) {
 1033    -1 		for (var selector in constants.nameDefaults) {
   -1  1128 		for (const selector in constants.nameDefaults) {
 1034  1129 			if (el.matches(selector)) {
 1035  1130 				ret = constants.nameDefaults[selector];
 1036  1131 			}
@@ -1052,29 +1147,29 @@ var getName = function(el, recursive, visited, directReference) {
 1052  1147 		ret = ' ';
 1053  1148 	}
 1054  1149 
 1055    -1 	var before = getPseudoContent(el, ':before');
 1056    -1 	var after = getPseudoContent(el, ':after');
   -1  1150 	const before = getPseudoContent(el, ':before');
   -1  1151 	const after = getPseudoContent(el, ':after');
 1057  1152 	return before + ret + after;
 1058  1153 };
 1059  1154 
 1060    -1 var getNameTrimmed = function(el) {
   -1  1155 const getNameTrimmed = function(el) {
 1061  1156 	return getName(el).replace(/\s+/g, ' ').trim();
 1062  1157 };
 1063  1158 
 1064    -1 var getDescription = function(el) {
 1065    -1 	var ret = '';
   -1  1159 const getDescription = function(el) {
   -1  1160 	let ret = '';
 1066  1161 
 1067  1162 	if (el.matches('[aria-describedby]')) {
 1068    -1 		var ids = el.getAttribute('aria-describedby').split(/\s+/);
 1069    -1 		var strings = ids.map(id => {
 1070    -1 			var label = document.getElementById(id);
   -1  1163 		const ids = el.getAttribute('aria-describedby').split(/\s+/);
   -1  1164 		const strings = ids.map(id => {
   -1  1165 			const label = document.getElementById(id);
 1071  1166 			return label ? getName(label, true) : '';
 1072  1167 		});
 1073  1168 		ret = strings.join(' ');
 1074  1169 	} else if (el.matches('[aria-description]')) {
 1075  1170 		ret = el.getAttribute('aria-description');
 1076  1171 	} else if (el.matches('svg *')) {
 1077    -1 		var svgDesc = el.querySelector('desc');
   -1  1172 		const svgDesc = el.querySelector('desc');
 1078  1173 		if (svgDesc && svgDesc.parentElement === el) {
 1079  1174 			ret = svgDesc.textContent;
 1080  1175 		}
@@ -1097,34 +1192,32 @@ module.exports = {
 1097  1192 };
 1098  1193 
 1099  1194 },{"./atree.js":2,"./constants.js":4,"./query.js":6}],6:[function(require,module,exports){
 1100    -1 var attrs = require('./attrs.js');
 1101    -1 var atree = require('./atree.js');
 1102    -1 
   -1  1195 const attrs = require('./attrs.js');
   -1  1196 const atree = require('./atree.js');
 1103  1197 
 1104    -1 var matches = function(el, selector) {
 1105    -1 	var actual;
 1106  1198 
   -1  1199 const matches = function(el, selector) {
 1107  1200 	if (selector.substr(0, 1) === ':') {
 1108    -1 		var attr = selector.substr(1);
   -1  1201 		const attr = selector.substr(1);
 1109  1202 		return attrs.getAttribute(el, attr);
 1110  1203 	} else if (selector.substr(0, 1) === '[') {
 1111    -1 		var match = /\[([a-z]+)="(.*)"\]/.exec(selector);
 1112    -1 		actual = attrs.getAttribute(el, match[1]);
 1113    -1 		var rawValue = match[2];
   -1  1204 		const match = /\[([a-z]+)="(.*)"\]/.exec(selector);
   -1  1205 		const actual = attrs.getAttribute(el, match[1]);
   -1  1206 		const rawValue = match[2];
 1114  1207 		return actual.toString() === rawValue;
 1115  1208 	} else {
 1116  1209 		return attrs.hasRole(el, selector.split(','));
 1117  1210 	}
 1118  1211 };
 1119  1212 
 1120    -1 var _querySelector = function(all) {
 1121    -1 	return function(root, role) {
 1122    -1 		var results = [];
   -1  1213 const _querySelector = function(all) {
   -1  1214 	return function(root, selector) {
   -1  1215 		const results = [];
 1123  1216 		try {
 1124  1217 			atree.walk(root, node => {
 1125  1218 				if (node.nodeType === node.ELEMENT_NODE) {
 1126  1219 					// FIXME: skip hidden elements
 1127    -1 					if (matches(node, role)) {
   -1  1220 					if (matches(node, selector)) {
 1128  1221 						results.push(node);
 1129  1222 						if (!all) {
 1130  1223 							throw 'StopIteration';
@@ -1141,7 +1234,7 @@ var _querySelector = function(all) {
 1141  1234 	};
 1142  1235 };
 1143  1236 
 1144    -1 var closest = function(el, selector) {
   -1  1237 const closest = function(el, selector) {
 1145  1238 	return atree.searchUp(el, candidate => {
 1146  1239 		if (candidate.nodeType === candidate.ELEMENT_NODE) {
 1147  1240 			return matches(candidate, selector);

diff --git a/package.json b/package.json

@@ -1,6 +1,6 @@
    1     1 {
    2     2   "name": "aria-api",
    3    -1   "version": "0.5.0",
   -1     3   "version": "0.6.0",
    4     4   "description": "Access ARIA information from JavaScript",
    5     5   "main": "index.js",
    6     6   "keywords": [