no-noninteractive-element-interactions.js 4.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports["default"] = void 0;
  7. var _ariaQuery = require("aria-query");
  8. var _jsxAstUtils = require("jsx-ast-utils");
  9. var _arrayIncludes = _interopRequireDefault(require("array-includes"));
  10. var _hasown = _interopRequireDefault(require("hasown"));
  11. var _schemas = require("../util/schemas");
  12. var _getElementType = _interopRequireDefault(require("../util/getElementType"));
  13. var _isAbstractRole = _interopRequireDefault(require("../util/isAbstractRole"));
  14. var _isContentEditable = _interopRequireDefault(require("../util/isContentEditable"));
  15. var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
  16. var _isInteractiveElement = _interopRequireDefault(require("../util/isInteractiveElement"));
  17. var _isInteractiveRole = _interopRequireDefault(require("../util/isInteractiveRole"));
  18. var _isNonInteractiveElement = _interopRequireDefault(require("../util/isNonInteractiveElement"));
  19. var _isNonInteractiveRole = _interopRequireDefault(require("../util/isNonInteractiveRole"));
  20. var _isPresentationRole = _interopRequireDefault(require("../util/isPresentationRole"));
  21. /**
  22. * @fileoverview Enforce non-interactive elements have no interactive handlers.
  23. * @author Jese Beach
  24. *
  25. */
  26. // ----------------------------------------------------------------------------
  27. // Rule Definition
  28. // ----------------------------------------------------------------------------
  29. var errorMessage = 'Non-interactive elements should not be assigned mouse or keyboard event listeners.';
  30. var defaultInteractiveProps = [].concat(_jsxAstUtils.eventHandlersByType.focus, _jsxAstUtils.eventHandlersByType.image, _jsxAstUtils.eventHandlersByType.keyboard, _jsxAstUtils.eventHandlersByType.mouse);
  31. var schema = (0, _schemas.generateObjSchema)({
  32. handlers: _schemas.arraySchema
  33. });
  34. var _default = exports["default"] = {
  35. meta: {
  36. docs: {
  37. url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-noninteractive-element-interactions.md',
  38. description: 'Non-interactive elements should not be assigned mouse or keyboard event listeners.'
  39. },
  40. schema: [schema]
  41. },
  42. create: function create(context) {
  43. var options = context.options;
  44. var elementType = (0, _getElementType["default"])(context);
  45. return {
  46. JSXOpeningElement: function (_JSXOpeningElement) {
  47. function JSXOpeningElement(_x) {
  48. return _JSXOpeningElement.apply(this, arguments);
  49. }
  50. JSXOpeningElement.toString = function () {
  51. return _JSXOpeningElement.toString();
  52. };
  53. return JSXOpeningElement;
  54. }(function (node) {
  55. var attributes = node.attributes;
  56. var type = elementType(node);
  57. var config = options[0] || {};
  58. var interactiveProps = config.handlers || defaultInteractiveProps;
  59. // Allow overrides from rule configuration for specific elements and roles.
  60. if ((0, _hasown["default"])(config, type)) {
  61. attributes = attributes.filter(function (attr) {
  62. return attr.type !== 'JSXSpreadAttribute' && !(0, _arrayIncludes["default"])(config[type], (0, _jsxAstUtils.propName)(attr));
  63. });
  64. }
  65. var hasInteractiveProps = interactiveProps.some(function (prop) {
  66. return (0, _jsxAstUtils.hasProp)(attributes, prop) && (0, _jsxAstUtils.getPropValue)((0, _jsxAstUtils.getProp)(attributes, prop)) != null;
  67. });
  68. if (!_ariaQuery.dom.has(type)) {
  69. // Do not test higher level JSX components, as we do not know what
  70. // low-level DOM element this maps to.
  71. return;
  72. }
  73. if (!hasInteractiveProps || (0, _isContentEditable["default"])(type, attributes) || (0, _isHiddenFromScreenReader["default"])(type, attributes) || (0, _isPresentationRole["default"])(type, attributes)) {
  74. // Presentation is an intentional signal from the author that this
  75. // element is not meant to be perceivable. For example, a click screen
  76. // to close a dialog .
  77. return;
  78. }
  79. if ((0, _isInteractiveElement["default"])(type, attributes) || (0, _isInteractiveRole["default"])(type, attributes) || !(0, _isNonInteractiveElement["default"])(type, attributes) && !(0, _isNonInteractiveRole["default"])(type, attributes) || (0, _isAbstractRole["default"])(type, attributes)) {
  80. // This rule has no opinion about abtract roles.
  81. return;
  82. }
  83. // Visible, non-interactive elements should not have an interactive handler.
  84. context.report({
  85. node,
  86. message: errorMessage
  87. });
  88. })
  89. };
  90. }
  91. };
  92. module.exports = exports.default;