Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds labelling for breadcrumb v9 #62

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ We currently cover the following components:
- [x] TextArea
- [x] Toolbar
- [] Tooltip
- [x] Breadcrumb
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ Any use of third-party trademarks or logos are subject to those third-party's po

| Name                                          | Description | 🔧 |
| :----------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- |
| [breadcrumb-needs-labelling-v9](docs/rules/breadcrumb-needs-labelling-v9.md) | All interactive elements must have an accessible name | |
| [checkbox-needs-labelling-v9](docs/rules/checkbox-needs-labelling-v9.md) | Accessibility: Checkbox without label must have an accessible and visual label: aria-labelledby | |
| [combobox-needs-labelling-v9](docs/rules/combobox-needs-labelling-v9.md) | All interactive elements must have an accessible name | |
| [icon-text-content-button-does-not-need-aria](docs/rules/icon-text-content-button-does-not-need-aria.md) | Accessibility: an image button with text content does not need aria labelling. The button already has an accessible name and the aria-label or aria-labelledby will override the text content for screen reader users. | |
Expand Down
35 changes: 35 additions & 0 deletions docs/rules/breadcrumb-needs-labelling-v9.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# All interactive elements must have an accessible name (`@microsoft/fluentui-jsx-a11y/breadcrumb-needs-labelling-v9`)

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

Provide labels to identify all form controls, including text fields, checkboxes, radio buttons, and drop-down menus. In most cases, this is done by using the label element.

<https://www.w3.org/WAI/tutorials/forms/labels/>

All interactive elements must have an accessible name.

## Rule Details

This rule aims to...

Examples of **incorrect** code for this rule:

```jsx
<div>
<label>Breadcrumb default example<label>
<Breadcrumb ></BreadCrumb>
</div>
<Breadcrumb></Breadcrumb>
```

Examples of **correct** code for this rule:

```jsx
<Breadcrumb aria-label="Breadcrumb default example">
<div>
<label id="my-label">Breadcrumb default example<label>
<Breadcrumb aria-labelledby="my-label"><BreadCrumb>
</div>
<label>Breadcrumb default example<Breadcrumb></Breadcrumb></label>
```

7 changes: 7 additions & 0 deletions docs/rules/no-empty-components-v9.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Examples of **incorrect** code for this rule:
<Label></Label>
```

```jsx
<Breadcrumb></Breadcrumb>
```

Examples of **correct** code for this rule:

```jsx
Expand All @@ -34,3 +38,6 @@ Examples of **correct** code for this rule:
<Text>This is an example of the Text component's usage.</Text>
```

```jsx
<Breadcrumb><BreadcrumbItem><BreadcrumbButton>Item 1</BreadcrumbButton></BreadcrumbItem></Breadcrumb>
```
59 changes: 59 additions & 0 deletions lib/rules/breadcrumb-needs-labelling-v9.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

"use strict";

const { hasNonEmptyProp } = require("../util/hasNonEmptyProp");
var elementType = require("jsx-ast-utils").elementType;
const { hasAssociatedLabelViaAriaLabelledBy, isInsideLabelTag } = require("../util/labelUtils");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
// possible error messages for the rule
messages: {
noUnlabelledBreadcrumb: "Accessibility: Breadcrumb must have an accessible label"
},
// "problem" means the rule is identifying code that either will cause an error or may cause a confusing behavior: https://eslint.org/docs/latest/developer-guide/working-with-rules
type: "problem",
docs: {
description: "All interactive elements must have an accessible name",
recommended: false,
url: "https://www.w3.org/TR/html-aria/" // 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 {
// visitor functions for different types of nodes
JSXOpeningElement(node) {
// if it is not a Breadcrumb, return
if (elementType(node) !== "Breadcrumb") {
return;
}

// if the Breadcrumb has a label, if the Breadcrumb has an associated label, return
if (
hasNonEmptyProp(node.attributes, "aria-label") || //aria-label
isInsideLabelTag(context) || // wrapped in label
hasAssociatedLabelViaAriaLabelledBy(node, context) // aria-labelledby
) {
return;
}

// if it has no visual labelling, report error
context.report({
node,
messageId: `noUnlabelledBreadcrumb`
});
}
};
}
};

4 changes: 3 additions & 1 deletion lib/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ module.exports = {
"image-button-missing-aria-v9": require("./image-button-missing-aria-v9"),
"toolbar-missing-aria-v9": require("./toolbar-missing-aria-v9"),
"combobox-needs-labelling-v9": require("./combobox-needs-labelling-v9"),
"no-empty-components-v9": require("./no-empty-components-v9")
"no-empty-components-v9": require("./no-empty-components-v9"),
"breadcrumb-needs-labelling-v9": require("./breadcrumb-needs-labelling-v9")
};

2 changes: 1 addition & 1 deletion lib/rules/no-empty-components-v9.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ var elementType = require("jsx-ast-utils").elementType;
// Rule Definition
//------------------------------------------------------------------------------
// Define an array of allowed component names
const allowedComponents = ["Text", "Label", "Combobox"];
const allowedComponents = ["Text", "Label", "Combobox", "Breadcrumb"];

/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
Expand Down
46 changes: 46 additions & 0 deletions tests/lib/rules/breadcrumb-needs-labelling-v9.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const rule = require("../../../lib/rules/breadcrumb-needs-labelling-v9"),
RuleTester = require("eslint").RuleTester;

RuleTester.setDefaultConfig({
parserOptions: {
ecmaVersion: 6,
ecmaFeatures: {
jsx: true
}
}
});

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

const ruleTester = new RuleTester();
ruleTester.run("breadcrumb-needs-labelling-v9", rule, {
valid: [
// give me some code that won't trigger a warning
'<Breadcrumb aria-label="Breadcrumb default example"></Breadcrumb>',
"<label>Breadcrumb default example<Breadcrumb></Breadcrumb></label>",
'<div><label id="my-label">Breadcrumb default example</label><Breadcrumb aria-labelledby="my-label"></Breadcrumb></div>',
'<div><Label id="my-label">Breadcrumb default example</Label><Breadcrumb aria-labelledby="my-label"></Breadcrumb></div>'
],
invalid: [
{
code: '<div><Label id="my-label">Breadcrumb default example</Label><Breadcrumb></Breadcrumb></div>',
errors: [{ messageId: "noUnlabelledBreadcrumb" }]
},
{
code: "<Breadcrumb></Breadcrumb>",
errors: [{ messageId: "noUnlabelledBreadcrumb" }]
}
]
});

5 changes: 5 additions & 0 deletions tests/lib/rules/no-empty-components-v9.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ ruleTester.run("no-empty-components-v9", rule, {
"<Label>Hello</Label>",
'<Text font="base">This is the default font</Text>',
'<Label size="small">Small</Label>',
"<Breadcrumb><BreadcrumbItem><BreadcrumbButton>Item 1</BreadcrumbButton></BreadcrumbItem></Breadcrumb>",
'<Combobox aria-labelledby={comboId} placeholder="Select an animal" {...props}>{options.map((option) => (<Option key={option} disabled={option === "Ferret"}>{option}</Option>))}</Combobox>'
],

Expand All @@ -38,6 +39,10 @@ ruleTester.run("no-empty-components-v9", rule, {
code: "<Text></Text>",
errors: [{ messageId: "noEmptyComponents" }]
},
{
code: "<Breadcrumb></Breadcrumb>",
errors: [{ messageId: "noEmptyComponents" }]
},
{
code: "<Label></Label>",
errors: [{ messageId: "noEmptyComponents" }]
Expand Down
Loading