Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
shweta786 authored Sep 20, 2024
2 parents adec94a + 00bd24a commit 7c6493a
Show file tree
Hide file tree
Showing 126 changed files with 1,659 additions and 1,818 deletions.
2 changes: 1 addition & 1 deletion COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ We currently cover the following components:
- [N/A] Divider
- [] Drawer
- [X] Dropdown
- [] Field
- [x] Field
- [N/A] FluentProvider
- [] Image
- [] InfoLabel
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ Any use of third-party trademarks or logos are subject to those third-party's po
| [dialogbody-needs-title-content-and-actions](docs/rules/dialogbody-needs-title-content-and-actions.md) | A DialogBody should have a header(DialogTitle), content(DialogContent), and footer(DialogActions) | ✅ | | |
| [dialogsurface-needs-aria](docs/rules/dialogsurface-needs-aria.md) | DialogueSurface need accessible labelling: aria-describedby on DialogueSurface and aria-label or aria-labelledby(if DialogueTitle is missing) | ✅ | | |
| [dropdown-needs-labelling](docs/rules/dropdown-needs-labelling.md) | Accessibility: Dropdown menu must have an id and it needs to be linked via htmlFor of a Label | ✅ | | |
| [field-needs-labelling](docs/rules/field-needs-labelling.md) | Accessibility: Field must have either label, validationMessage and hint attributes | ✅ | | |
| [image-button-missing-aria](docs/rules/image-button-missing-aria.md) | Accessibility: Image buttons must have accessible labelling: title, aria-label, aria-labelledby, aria-describedby | ✅ | | |
| [input-components-require-accessible-name](docs/rules/input-components-require-accessible-name.md) | Accessibility: Input fields must have accessible labelling: aria-label, aria-labelledby or an associated label | ✅ | | |
| [link-missing-labelling](docs/rules/link-missing-labelling.md) | Accessibility: Image links must have an accessible name. Add either text content, labelling to the image or labelling to the link itself. | ✅ | | 🔧 |
Expand Down
83 changes: 56 additions & 27 deletions dist/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
console.log("Loading my-eslint-plugin");
const prefer_aria_over_title_attribute_1 = __importDefault(require("./rules/prefer-aria-over-title-attribute"));
const checkbox_needs_labelling_1 = __importDefault(require("./rules/checkbox-needs-labelling"));
const image_button_missing_aria_1 = __importDefault(require("./rules/buttons/image-button-missing-aria"));
const link_missing_labelling_1 = __importDefault(require("./rules/link-missing-labelling"));
const input_components_require_accessible_name_1 = __importDefault(require("./rules/input-components-require-accessible-name"));
const menu_item_needs_labelling_1 = __importDefault(require("./rules/menu-item-needs-labelling"));
const switch_needs_labelling_1 = __importDefault(require("./rules/switch-needs-labelling"));
const toolbar_missing_aria_1 = __importDefault(require("./rules/toolbar-missing-aria"));
const combobox_needs_labelling_1 = __importDefault(require("./rules/combobox-needs-labelling"));
const no_empty_components_1 = __importDefault(require("./rules/no-empty-components"));
const accordion_header_needs_labelling_1 = __importDefault(require("./rules/accordion-header-needs-labelling"));
const accordion_item_needs_header_and_panel_1 = __importDefault(require("./rules/accordion-item-needs-header-and-panel"));
const compound_button_needs_labelling_1 = __importDefault(require("./rules/buttons/compound-button-needs-labelling"));
const no_empty_buttons_1 = __importDefault(require("./rules/buttons/no-empty-buttons"));
const spin_button_needs_labelling_1 = __importDefault(require("./rules/spin-button-needs-labelling"));
const spin_button_unrecommended_labelling_1 = __importDefault(require("./rules/spin-button-unrecommended-labelling"));
const breadcrumb_needs_labelling_1 = __importDefault(require("./rules/breadcrumb-needs-labelling"));
const dropdown_needs_labelling_1 = __importDefault(require("./rules/dropdown-needs-labelling"));
const tooltip_not_recommended_1 = __importDefault(require("./rules/tooltip-not-recommended"));
const avatar_needs_name_1 = __importDefault(require("./rules/avatar-needs-name"));
const radio_button_missing_label_1 = __importDefault(require("./rules/radio-button-missing-label"));
const radiogroup_missing_label_1 = __importDefault(require("./rules/radiogroup-missing-label"));
const dialogbody_needs_title_content_and_actions_1 = __importDefault(require("./rules/dialogbody-needs-title-content-and-actions"));
const dialogsurface_needs_aria_1 = __importDefault(require("./rules/dialogsurface-needs-aria"));
const spinner_needs_labelling_1 = __importDefault(require("./rules/spinner-needs-labelling"));
const badge_needs_accessible_name_1 = __importDefault(require("./rules/badge-needs-accessible-name"));
const progressbar_needs_labelling_1 = __importDefault(require("./rules/progressbar-needs-labelling"));
const field_needs_labelling_1 = __importDefault(require("./rules/field-needs-labelling"));
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
Expand All @@ -16,33 +43,34 @@ const prefer_aria_over_title_attribute_1 = __importDefault(require("./rules/pref
// import all rules in lib/rules
module.exports = {
rules: {
"checkbox-needs-labelling": require("./rules/checkbox-needs-labelling"),
"image-button-missing-aria": require("./rules/buttons/image-button-missing-aria"),
"link-missing-labelling": require("./rules/link-missing-labelling"),
"input-components-require-accessible-name": require("./rules/input-components-require-accessible-name"),
"menu-item-needs-labelling": require("./rules/menu-item-needs-labelling"),
"switch-needs-labelling": require("./rules/switch-needs-labelling"),
"toolbar-missing-aria": require("./rules/toolbar-missing-aria"),
"combobox-needs-labelling": require("./rules/combobox-needs-labelling"),
"no-empty-components": require("./rules/no-empty-components"),
"accordion-header-needs-labelling": require("./rules/accordion-header-needs-labelling"),
"accordion-item-needs-header-and-panel": require("./rules/accordion-item-needs-header-and-panel"),
"compound-button-needs-labelling": require("./rules/buttons/compound-button-needs-labelling"),
"no-empty-buttons": require("./rules/buttons/no-empty-buttons"),
"spin-button-needs-labelling": require("./rules/spin-button-needs-labelling"),
"spin-button-unrecommended-labelling": require("./rules/spin-button-unrecommended-labelling"),
"breadcrumb-needs-labelling": require("./rules/breadcrumb-needs-labelling"),
"dropdown-needs-labelling": require("./rules/dropdown-needs-labelling"),
"tooltip-not-recommended": require("./rules/tooltip-not-recommended"),
"avatar-needs-name": require("./rules/avatar-needs-name"),
"radio-button-missing-label": require("./rules/radio-button-missing-label"),
"radiogroup-missing-label": require("./rules/radiogroup-missing-label"),
"checkbox-needs-labelling": checkbox_needs_labelling_1.default,
"image-button-missing-aria": image_button_missing_aria_1.default,
"link-missing-labelling": link_missing_labelling_1.default,
"input-components-require-accessible-name": input_components_require_accessible_name_1.default,
"menu-item-needs-labelling": menu_item_needs_labelling_1.default,
"switch-needs-labelling": switch_needs_labelling_1.default,
"toolbar-missing-aria": toolbar_missing_aria_1.default,
"combobox-needs-labelling": combobox_needs_labelling_1.default,
"no-empty-components": no_empty_components_1.default,
"accordion-header-needs-labelling": accordion_header_needs_labelling_1.default,
"accordion-item-needs-header-and-panel": accordion_item_needs_header_and_panel_1.default,
"compound-button-needs-labelling": compound_button_needs_labelling_1.default,
"no-empty-buttons": no_empty_buttons_1.default,
"spin-button-needs-labelling": spin_button_needs_labelling_1.default,
"spin-button-unrecommended-labelling": spin_button_unrecommended_labelling_1.default,
"breadcrumb-needs-labelling": breadcrumb_needs_labelling_1.default,
"dropdown-needs-labelling": dropdown_needs_labelling_1.default,
"tooltip-not-recommended": tooltip_not_recommended_1.default,
"avatar-needs-name": avatar_needs_name_1.default,
"radio-button-missing-label": radio_button_missing_label_1.default,
"radiogroup-missing-label": radiogroup_missing_label_1.default,
"prefer-aria-over-title-attribute": prefer_aria_over_title_attribute_1.default,
"dialogbody-needs-title-content-and-actions": require("./rules/dialogbody-needs-title-content-and-actions"),
"dialogsurface-needs-aria": require("./rules/dialogsurface-needs-aria"),
"spinner-needs-labelling": require("./rules/spinner-needs-labelling"),
"badge-needs-accessible-name": require("./rules/badge-needs-accessible-name"),
"progressbar-needs-labelling": require("./rules/progressbar-needs-labelling")
"dialogbody-needs-title-content-and-actions": dialogbody_needs_title_content_and_actions_1.default,
"dialogsurface-needs-aria": dialogsurface_needs_aria_1.default,
"spinner-needs-labelling": spinner_needs_labelling_1.default,
"badge-needs-accessible-name": badge_needs_accessible_name_1.default,
"progressbar-needs-labelling": progressbar_needs_labelling_1.default,
"field-needs-labelling": field_needs_labelling_1.default
},
configs: {
recommended: {
Expand Down Expand Up @@ -72,7 +100,8 @@ module.exports = {
"@microsoft/fluentui-jsx-a11y/dialogbody-needs-title-content-and-actions": "error",
"@microsoft/fluentui-jsx-a11y/dialogsurface-needs-aria": "error",
"@microsoft/fluentui-jsx-a11y/spinner-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/progressbar-needs-labelling": "error"
"@microsoft/fluentui-jsx-a11y/progressbar-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/field-needs-labelling": "error"
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions dist/lib/rules/accordion-header-needs-labelling.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
declare const _exports: import("eslint").Rule.RuleModule;
export = _exports;
import { TSESTree } from "@typescript-eslint/utils";
declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingAriaLabel", [], {
JSXElement(node: TSESTree.JSXElement): void;
}>;
export default rule;
39 changes: 20 additions & 19 deletions dist/lib/rules/accordion-header-needs-labelling.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
"use strict";
const { hasNonEmptyProp } = require("../util/hasNonEmptyProp");
const { hasToolTipParent } = require("../util/hasTooltipParent");
const { hasTextContentChild } = require("../util/hasTextContentChild");
const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils");
var hasProp = require("jsx-ast-utils").hasProp;
var elementType = require("jsx-ast-utils").elementType;
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("@typescript-eslint/utils");
const jsx_ast_utils_1 = require("jsx-ast-utils");
const hasNonEmptyProp_1 = require("../util/hasNonEmptyProp");
const hasTooltipParent_1 = require("../util/hasTooltipParent");
const hasTextContentChild_1 = require("../util/hasTextContentChild");
const labelUtils_1 = require("../util/labelUtils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({
defaultOptions: [],
meta: {
messages: {
missingAriaLabel: "Accessibility: the accordion header must have an accessible name"
},
type: "problem", // `problem`, `suggestion`, or `layout`
docs: {
description: "The accordion header is a button and it needs an accessibile name e.g. text content, aria-label, aria-labelledby.",
recommended: false,
url: null // URL to the documentation page for this rule
recommended: false
},
fixable: null, // Or `code` or `whitespace`
schema: [] // Add a schema if the rule has options
},
// create (function) returns an object with methods that ESLint calls to “visit” nodes while traversing the abstract syntax tree
Expand All @@ -32,26 +31,27 @@ module.exports = {
JSXElement(node) {
const openingElement = node.openingElement;
// if it is not a AccordionHeader, return
if (elementType(openingElement) !== "AccordionHeader") {
if ((0, jsx_ast_utils_1.elementType)(openingElement) !== "AccordionHeader") {
return;
}
// if it has text content, return
if (hasTextContentChild(node)) {
if ((0, hasTextContentChild_1.hasTextContentChild)(node)) {
return;
}
// if it is not an icon button, return
if (!hasProp(openingElement.attributes, "icon") && !hasProp(openingElement.attributes, "expandIcon")) {
if (!(0, jsx_ast_utils_1.hasProp)(openingElement.attributes, "icon") &&
!(0, jsx_ast_utils_1.hasProp)(openingElement.attributes, "expandIcon")) {
return;
}
// if it has a tooltip parent, return
if (hasToolTipParent(context)) {
if ((0, hasTooltipParent_1.hasToolTipParent)(context)) {
return;
}
// the button has an associated label
if (hasAssociatedLabelViaAriaLabelledBy(openingElement, context)) {
if ((0, labelUtils_1.hasAssociatedLabelViaAriaLabelledBy)(openingElement, context)) {
return;
}
const hasAccessibleLabelling = hasNonEmptyProp(openingElement.attributes, "title") || hasNonEmptyProp(openingElement.attributes, "aria-label");
const hasAccessibleLabelling = (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "title") || (0, hasNonEmptyProp_1.hasNonEmptyProp)(openingElement.attributes, "aria-label");
// if it has no accessible name, report error
if (!hasAccessibleLabelling) {
context.report({
Expand All @@ -62,4 +62,5 @@ module.exports = {
}
};
}
};
});
exports.default = rule;
7 changes: 5 additions & 2 deletions dist/lib/rules/accordion-item-needs-header-and-panel.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
declare const _exports: import("eslint").Rule.RuleModule;
export = _exports;
import { TSESTree } from "@typescript-eslint/utils";
declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"accordionItemOneHeaderOnePanel", [], {
JSXOpeningElement(node: TSESTree.JSXOpeningElement): void;
}>;
export default rule;
25 changes: 16 additions & 9 deletions dist/lib/rules/accordion-item-needs-header-and-panel.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("@typescript-eslint/utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
const rule = utils_1.ESLintUtils.RuleCreator.withoutDocs({
defaultOptions: [],
meta: {
messages: {
accordionItemOneHeaderOnePanel: "ensure AccordionItem has exactly one header and one panel"
},
type: "problem", // `problem`, `suggestion`, or `layout`
docs: {
description: "An AccordionItem needs exactly one header and one panel",
recommended: true,
recommended: "strict",
url: "https://www.w3.org/WAI/ARIA/apg/patterns/accordion/" // URL to the documentation page for this rule
},
fixable: null, // Or `code` or `whitespace`
schema: [] // Add a schema if the rule has options
},
create(context) {
return {
JSXOpeningElement(node) {
if (node.name.name !== "AccordionItem") {
if (node.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier && node.name.name !== "AccordionItem") {
return;
}
if (!(node.parent && node.parent.type === utils_1.AST_NODE_TYPES.JSXElement)) {
return;
}
const children = node.parent.children.filter(child => child.type === "JSXElement");
const hasOneHeader = children.filter(child => child.openingElement.name.name === "AccordionHeader").length === 1;
const hasOnePanel = children.filter(child => child.openingElement.name.name === "AccordionPanel").length === 1;
const hasOneHeader = children.filter(child => child.openingElement.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier &&
child.openingElement.name.name === "AccordionHeader").length === 1;
const hasOnePanel = children.filter(child => child.openingElement.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier &&
child.openingElement.name.name === "AccordionPanel").length === 1;
if (!hasOneHeader || !hasOnePanel || children.length !== 2) {
context.report({
node,
Expand All @@ -37,4 +43,5 @@ module.exports = {
}
};
}
};
});
exports.default = rule;
20 changes: 5 additions & 15 deletions dist/lib/rules/avatar-needs-name.d.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
export namespace meta {
namespace messages {
let missingAriaLabel: string;
}
let type: string;
namespace docs {
let description: string;
let recommended: boolean;
let url: string;
}
let schema: never[];
}
export function create(context: any): {
JSXOpeningElement(node: any): void;
};
import { TSESTree } from "@typescript-eslint/utils";
declare const rule: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<"missingAriaLabel", [], {
JSXOpeningElement(node: TSESTree.JSXOpeningElement): void;
}>;
export default rule;
Loading

0 comments on commit 7c6493a

Please sign in to comment.