isInteractiveElement.js
5.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _ariaQuery = require("aria-query");
var _axobjectQuery = require("axobject-query");
var _arrayIncludes = _interopRequireDefault(require("array-includes"));
var _attributesComparator = _interopRequireDefault(require("./attributesComparator"));
var domKeys = (0, _toConsumableArray2["default"])(_ariaQuery.dom.keys());
var roleKeys = (0, _toConsumableArray2["default"])(_ariaQuery.roles.keys());
var elementRoleEntries = (0, _toConsumableArray2["default"])(_ariaQuery.elementRoles);
var nonInteractiveRoles = new Set(roleKeys.filter(function (name) {
var role = _ariaQuery.roles.get(name);
return !role["abstract"] // 'toolbar' does not descend from widget, but it does support
// aria-activedescendant, thus in practice we treat it as a widget.
&& name !== 'toolbar' && !role.superClass.some(function (classes) {
return (0, _arrayIncludes["default"])(classes, 'widget');
});
}).concat( // The `progressbar` is descended from `widget`, but in practice, its
// value is always `readonly`, so we treat it as a non-interactive role.
'progressbar'));
var interactiveRoles = new Set(roleKeys.filter(function (name) {
var role = _ariaQuery.roles.get(name);
return !role["abstract"] // The `progressbar` is descended from `widget`, but in practice, its
// value is always `readonly`, so we treat it as a non-interactive role.
&& name !== 'progressbar' && role.superClass.some(function (classes) {
return (0, _arrayIncludes["default"])(classes, 'widget');
});
}).concat( // 'toolbar' does not descend from widget, but it does support
// aria-activedescendant, thus in practice we treat it as a widget.
'toolbar'));
var nonInteractiveElementRoleSchemas = elementRoleEntries.reduce(function (accumulator, _ref) {
var _ref2 = (0, _slicedToArray2["default"])(_ref, 2),
elementSchema = _ref2[0],
roleSet = _ref2[1];
if ((0, _toConsumableArray2["default"])(roleSet).every(function (role) {
return nonInteractiveRoles.has(role);
})) {
accumulator.push(elementSchema);
}
return accumulator;
}, []);
var interactiveElementRoleSchemas = elementRoleEntries.reduce(function (accumulator, _ref3) {
var _ref4 = (0, _slicedToArray2["default"])(_ref3, 2),
elementSchema = _ref4[0],
roleSet = _ref4[1];
if ((0, _toConsumableArray2["default"])(roleSet).some(function (role) {
return interactiveRoles.has(role);
})) {
accumulator.push(elementSchema);
}
return accumulator;
}, []);
var interactiveAXObjects = new Set((0, _toConsumableArray2["default"])(_axobjectQuery.AXObjects.keys()).filter(function (name) {
return _axobjectQuery.AXObjects.get(name).type === 'widget';
}));
var interactiveElementAXObjectSchemas = (0, _toConsumableArray2["default"])(_axobjectQuery.elementAXObjects).reduce(function (accumulator, _ref5) {
var _ref6 = (0, _slicedToArray2["default"])(_ref5, 2),
elementSchema = _ref6[0],
AXObjectSet = _ref6[1];
if ((0, _toConsumableArray2["default"])(AXObjectSet).every(function (role) {
return interactiveAXObjects.has(role);
})) {
accumulator.push(elementSchema);
}
return accumulator;
}, []);
function checkIsInteractiveElement(tagName, attributes) {
function elementSchemaMatcher(elementSchema) {
return tagName === elementSchema.name && (0, _attributesComparator["default"])(elementSchema.attributes, attributes);
} // Check in elementRoles for inherent interactive role associations for
// this element.
var isInherentInteractiveElement = interactiveElementRoleSchemas.some(elementSchemaMatcher);
if (isInherentInteractiveElement) {
return true;
} // Check in elementRoles for inherent non-interactive role associations for
// this element.
var isInherentNonInteractiveElement = nonInteractiveElementRoleSchemas.some(elementSchemaMatcher);
if (isInherentNonInteractiveElement) {
return false;
} // Check in elementAXObjects for AX Tree associations for this element.
var isInteractiveAXElement = interactiveElementAXObjectSchemas.some(elementSchemaMatcher);
if (isInteractiveAXElement) {
return true;
}
return false;
}
/**
* Returns boolean indicating whether the given element is
* interactive on the DOM or not. Usually used when an element
* has a dynamic handler on it and we need to discern whether or not
* it's intention is to be interacted with on the DOM.
*/
var isInteractiveElement = function isInteractiveElement(tagName, attributes) {
// Do not test higher level JSX components, as we do not know what
// low-level DOM element this maps to.
if (!(0, _arrayIncludes["default"])(domKeys, tagName)) {
return false;
}
return checkIsInteractiveElement(tagName, attributes);
};
var _default = isInteractiveElement;
exports["default"] = _default;
module.exports = exports.default;