|
| 1 | +import { getProp, getLiteralPropValue } from 'jsx-ast-utils'; |
| 2 | +import DOMElements from './attributes/DOM.json'; |
| 3 | +import roles from './attributes/role.json'; |
| 4 | + |
| 5 | + |
| 6 | +const VALID_ROLES = Object.keys(roles) |
| 7 | + .filter(role => roles[role].interactive === false); |
| 8 | +/** |
| 9 | + * Returns boolean indicating whether the given element has a role |
| 10 | + * that is associated with a non-interactive component. Non-interactive roles |
| 11 | + * include `listitem`, `article`, or `dialog`. These are roles that indicate |
| 12 | + * for the most part containers. |
| 13 | + * |
| 14 | + * Elements with these roles should not respond or handle user interactions. |
| 15 | + * For example, an `onClick` handler should not be assigned to an element with |
| 16 | + * the role `listitem`. An element inside the `listitem`, like a button or a |
| 17 | + * link, should handle the click. |
| 18 | + * |
| 19 | + * This utility returns true for elements that are assigned a non-interactive |
| 20 | + * role. It will return false for elements that do not have a role. So whereas |
| 21 | + * a `div` might be considered non-interactive, for the purpose of this utility, |
| 22 | + * it is considered neither interactive nor non-interactive -- a determination |
| 23 | + * cannot be made in this case and false is returned. |
| 24 | + */ |
| 25 | +const isNonInteractiveRole = (tagName, attributes) => { |
| 26 | + // Do not test higher level JSX components, as we do not know what |
| 27 | + // low-level DOM element this maps to. |
| 28 | + if (Object.keys(DOMElements).indexOf(tagName) === -1) { |
| 29 | + return false; |
| 30 | + } |
| 31 | + |
| 32 | + const value = getLiteralPropValue(getProp(attributes, 'role')); |
| 33 | + |
| 34 | + // If value is undefined, then the role attribute will be dropped in the DOM. |
| 35 | + // If value is null, then getLiteralAttributeValue is telling us that the |
| 36 | + // value isn't in the form of a literal |
| 37 | + if (value === undefined || value === null) { |
| 38 | + return false; |
| 39 | + } |
| 40 | + |
| 41 | + const normalizedValues = String(value).toUpperCase().split(' '); |
| 42 | + const isNonInteractive = normalizedValues.every( |
| 43 | + val => VALID_ROLES.indexOf(val) > -1, |
| 44 | + ); |
| 45 | + |
| 46 | + return isNonInteractive; |
| 47 | +}; |
| 48 | + |
| 49 | +export default isNonInteractiveRole; |
0 commit comments