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 1d3bc93 + 0b06bfc commit e2eb17f
Show file tree
Hide file tree
Showing 21 changed files with 408 additions and 111 deletions.
2 changes: 1 addition & 1 deletion COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ We currently cover the following components:
- [] InfoLabel
- [x] Input
- [x] Label
- [] Link
- [x] Link
- [] Menu
- [] Menu
- [] MenuList
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ Any use of third-party trademarks or logos are subject to those third-party's po
| [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 | ✅ | | |
| [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 | ✅ | | |
| [image-link-missing-aria](docs/rules/image-link-missing-aria.md) | Accessibility: Image links must have an accessible name | ✅ | | 🔧 |
| [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. | ✅ | | 🔧 |
| [menu-item-needs-labelling](docs/rules/menu-item-needs-labelling.md) | Accessibility: MenuItem without label must have an accessible and visual label: aria-labelledby | ✅ | | |
| [no-empty-buttons](docs/rules/no-empty-buttons.md) | Accessibility: Button, ToggleButton, SplitButton, MenuButton, CompoundButton must either text content or icon or child component | ✅ | | |
| [no-empty-components](docs/rules/no-empty-components.md) | FluentUI components should not be empty | ✅ | | |
Expand Down
2 changes: 2 additions & 0 deletions dist/lib/applicableComponents/imageBasedComponents.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const fluentImageComponents: string[];
export const imageDomNodes: string[];
9 changes: 9 additions & 0 deletions dist/lib/applicableComponents/imageBasedComponents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
const fluentImageComponents = ["Image"];
const imageDomNodes = ["img"];
module.exports = {
fluentImageComponents,
imageDomNodes
};
1 change: 1 addition & 0 deletions dist/lib/applicableComponents/linkBasedComponents.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const linkBasedComponents: string[];
7 changes: 7 additions & 0 deletions dist/lib/applicableComponents/linkBasedComponents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
const linkBasedComponents = ["Link", "a"]; // , "BreadcrumbButton"
module.exports = {
linkBasedComponents
};
4 changes: 2 additions & 2 deletions dist/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module.exports = {
rules: {
"checkbox-needs-labelling": require("./rules/checkbox-needs-labelling"),
"image-button-missing-aria": require("./rules/buttons/image-button-missing-aria"),
"image-link-missing-aria": require("./rules/image-link-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"),
Expand Down Expand Up @@ -48,7 +48,7 @@ module.exports = {
recommended: {
rules: {
"@microsoft/fluentui-jsx-a11y/checkbox-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/image-link-missing-aria": "error",
"@microsoft/fluentui-jsx-a11y/link-missing-labelling": "error",
"@microsoft/fluentui-jsx-a11y/input-components-require-accessible-name": "error",
"@microsoft/fluentui-jsx-a11y/menu-item-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/switch-needs-labelling": "error",
Expand Down
2 changes: 2 additions & 0 deletions dist/lib/rules/link-missing-labelling.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare const _exports: import("eslint").Rule.RuleModule;
export = _exports;
76 changes: 76 additions & 0 deletions dist/lib/rules/link-missing-labelling.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
"use strict";
const { elementType } = require("jsx-ast-utils");
const { hasNonEmptyProp } = require("../util/hasNonEmptyProp");
const { hasTextContentChild } = require("../util/hasTextContentChild");
const { hasLabelledChildImage } = require("../util/hasLabelledChildImage");
const { linkBasedComponents } = require("../applicableComponents/linkBasedComponents");
const { hasAssociatedLabelViaAriaLabelledBy } = require("../util/labelUtils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
docs: {
description: "Accessibility: Image links must have an accessible name. Add either text content, labelling to the image or labelling to the link itself.",
recommended: true,
url: "https://www.w3.org/WAI/standards-guidelines/act/rules/c487ae/" // URL to the documentation page for this rule
},
messages: {
missingAriaLabel: "Accessibility Rule: Image links must have an accessible name. Link can have a title attribute or text content, or Image can have an aria-label, aria-labelledby, or title attribute.",
missingHref: "Links must have an href"
},
fixable: "code",
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
create(context) {
//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
return {
// visitor functions for different types of nodes
JSXElement(node) {
const openingElement = node.openingElement;
// if it's not a link based component, return
if (!linkBasedComponents.includes(elementType(openingElement))) {
return;
}
const hasHref = hasNonEmptyProp(openingElement.attributes, "href");
// check if the link has an href
if (!hasHref) {
context.report({
node,
messageId: `missingHref`
});
}
// if it has text content, return
if (hasTextContentChild(node)) {
return;
}
// if there is a containing image and it is labelled correctly, return
const hasAccessibleImage = hasLabelledChildImage(node);
if (hasAccessibleImage) {
return;
}
// Check if there is an accessible link
const linkHasAccessibleLabel = hasNonEmptyProp(openingElement.attributes, "title") ||
hasNonEmptyProp(openingElement.attributes, "aria-label") ||
hasAssociatedLabelViaAriaLabelledBy(openingElement, context);
if (linkHasAccessibleLabel) {
return;
}
// Report if there is no text content, accessible link or image
if (!linkHasAccessibleLabel || !hasAccessibleImage) {
context.report({
node,
messageId: `missingAriaLabel`
});
}
}
};
}
};
6 changes: 6 additions & 0 deletions dist/lib/util/hasLabelledChildImage.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* hasLabelledChildImage - determines if a component has text content as a child e.g. <Link href="https://www.bing.com" {...props}><Image src="https://www.w3schools.com/images/img_girl.jpg" alt="abc"></Image></Link>
* @param {*} node JSXElement
* @returns boolean
*/
export function hasLabelledChildImage(node: any): boolean;
37 changes: 37 additions & 0 deletions dist/lib/util/hasLabelledChildImage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
const { flattenChildren } = require("./flattenChildren");
const { hasProp, getPropValue } = require("jsx-ast-utils");
const { hasNonEmptyProp } = require("./hasNonEmptyProp");
const { fluentImageComponents, imageDomNodes } = require("../applicableComponents/imageBasedComponents");
const mergedImageComponents = [...fluentImageComponents, ...imageDomNodes];
/**
* hasLabelledChildImage - determines if a component has text content as a child e.g. <Link href="https://www.bing.com" {...props}><Image src="https://www.w3schools.com/images/img_girl.jpg" alt="abc"></Image></Link>
* @param {*} node JSXElement
* @returns boolean
*/
function hasLabelledChildImage(node) {
// no children
if (node.children == null || node.children == undefined || node.children.length === 0) {
return false;
}
// Check if there is an accessible image
const hasAccessibleImage = flattenChildren(node).some(child => {
console.log("mergedImageComponents.includes(child.openingElement.name.name)::: ", mergedImageComponents.includes(child.openingElement.name.name));
if (child.type === "JSXElement" && mergedImageComponents.includes(child.openingElement.name.name)) {
console.log("here 3");
return hasProp(child.openingElement.attributes, "aria-hidden") || getPropValue(child.openingElement.attributes, "alt")
? false
: hasNonEmptyProp(child.openingElement.attributes, "title") ||
hasNonEmptyProp(child.openingElement.attributes, "alt") ||
hasNonEmptyProp(child.openingElement.attributes, "aria-label") ||
hasNonEmptyProp(child.openingElement.attributes, "aria-labelledby");
}
return false;
});
return hasAccessibleImage;
}
module.exports = {
hasLabelledChildImage
};
2 changes: 1 addition & 1 deletion dist/lib/util/hasTextContentChild.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function hasTextContentChild(node) {
const result = node.children.filter(element => {
return element.type === "JSXText" && element.value.trim().length > 0;
});
return result != null;
return result.length !== 0;
}
module.exports = {
hasTextContentChild
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,19 @@
# Accessibility: Image links must have an accessible name (`@microsoft/fluentui-jsx-a11y/image-link-missing-aria`)
# Accessibility: Image links must have an accessible name. Add either text content, labelling to the image or labelling to the link itself (`@microsoft/fluentui-jsx-a11y/link-missing-labelling`)

💼 This rule is enabled in the ✅ `recommended` config.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

<!-- end auto-generated rule header -->

💼 This rule is enabled in the ✅ `recommended` config.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

<!-- end auto-generated rule header -->

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

<!-- end auto-generated rule header -->

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

All interactive elements must have an accessible name.

Links that contain Images without additional text content lack an accessible name.

Ways to fix:

1. Add a title, aria-label or aria-labelledby attribute or text content to the Link tag.
2. Add a title, aria-label or aria-labelledby attribute to the Image tag.
1. Add a title, aria-label or aria-labelledby attribute or text content to the Link element.
2. Add a alt text, title, aria-label or aria-labelledby attribute to the Image element.

<https://www.w3.org/WAI/standards-guidelines/act/rules/c487ae/>

Expand All @@ -50,11 +38,3 @@ Examples of **correct** code for this rule:
<Link href="#test"><Image src="/test.png" aria-label="This is an aria-label for the image link"/></Link>
<Link href="#test"><Image src="/test.png" aria-labelledby="id1"/></Link>
```

## When Not To Use It

Give a short description of when it would be appropriate to turn off this rule.

## Further Reading

If there are other links that describe the issue this rule addresses, please include them here in a bulleted list.
10 changes: 10 additions & 0 deletions lib/applicableComponents/imageBasedComponents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

const fluentImageComponents = ["Image"];
const imageDomNodes = ["img"];

module.exports = {
fluentImageComponents,
imageDomNodes
};
8 changes: 8 additions & 0 deletions lib/applicableComponents/linkBasedComponents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

const linkBasedComponents = ["Link", "a"]; // , "BreadcrumbButton"

module.exports = {
linkBasedComponents
};
4 changes: 2 additions & 2 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module.exports = {
rules: {
"checkbox-needs-labelling": require("./rules/checkbox-needs-labelling"),
"image-button-missing-aria": require("./rules/buttons/image-button-missing-aria"),
"image-link-missing-aria": require("./rules/image-link-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"),
Expand Down Expand Up @@ -47,7 +47,7 @@ module.exports = {
recommended: {
rules: {
"@microsoft/fluentui-jsx-a11y/checkbox-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/image-link-missing-aria": "error",
"@microsoft/fluentui-jsx-a11y/link-missing-labelling": "error",
"@microsoft/fluentui-jsx-a11y/input-components-require-accessible-name": "error",
"@microsoft/fluentui-jsx-a11y/menu-item-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/switch-needs-labelling": "error",
Expand Down
80 changes: 0 additions & 80 deletions lib/rules/image-link-missing-aria.js

This file was deleted.

Loading

0 comments on commit e2eb17f

Please sign in to comment.