Skip to content

Commit 26e7195

Browse files
authored
Merge pull request #132 from microsoft/user/aubreyquinn/tsConverstion
User/aubreyquinn/ts converstion
2 parents 362a590 + 536ae9f commit 26e7195

34 files changed

+1304
-550
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ Any use of third-party trademarks or logos are subject to those third-party's po
122122
| [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) | ✅ | | |
123123
| [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) | ✅ | | |
124124
| [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 | ✅ | | |
125-
| [field-needs-labelling](docs/rules/field-needs-labelling.md) | Accessibility: Field must have either label, validationMessage and hint attributes | ✅ | | |
125+
| [field-needs-labelling](docs/rules/field-needs-labelling.md) | Accessibility: Field must have label | ✅ | | |
126126
| [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 | ✅ | | |
127127
| [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 | ✅ | | |
128128
| [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. | ✅ | | 🔧 |
@@ -141,6 +141,6 @@ Any use of third-party trademarks or logos are subject to those third-party's po
141141
| [tablist-and-tabs-need-labelling](docs/rules/tablist-and-tabs-need-labelling.md) | This rule aims to ensure that Tabs with icons but no text labels have an accessible name and that Tablist is properly labeled. | ✅ | | |
142142
| [toolbar-missing-aria](docs/rules/toolbar-missing-aria.md) | Accessibility: Toolbars need accessible labelling: aria-label or aria-labelledby | ✅ | | |
143143
| [tooltip-not-recommended](docs/rules/tooltip-not-recommended.md) | Accessibility: Prefer text content or aria over a tooltip for these components MenuItem, SpinButton | ✅ | | |
144-
| [visual-label-better-than-aria-suggestion](docs/rules/visual-label-better-than-aria-suggestion.md) | Visual label is better than an aria-label | | ✅ | |
144+
| [visual-label-better-than-aria-suggestion](docs/rules/visual-label-better-than-aria-suggestion.md) | Visual label is better than an aria-label because sighted users can't read the aria-label text. | | ✅ | |
145145

146146
<!-- end auto-generated rules list -->

docs/rules/field-needs-labelling.md

+12-21
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
# Accessibility: Field must have either label, validationMessage and hint attributes (`@microsoft/fluentui-jsx-a11y/field-needs-labelling`)
1+
# Accessibility: Field must have label (`@microsoft/fluentui-jsx-a11y/field-needs-labelling`)
22

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

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

7-
Field must have `label` prop and either `validationMessage` or `hint` prop.
7+
Field must have `label` prop.
88

99
<https://www.w3.org/TR/html-aria/>
1010

1111
## Ways to fix
1212

1313
- Make sure that Field component has following props:
1414
- `label`
15-
- `validationMessage` or `hint`
1615

1716
## Rule Details
1817

@@ -21,41 +20,33 @@ This rule aims to make Field component accessible.
2120
Examples of **incorrect** code for this rule:
2221

2322
```jsx
24-
<Field
25-
label="Example field"
26-
validationState="success"
27-
>
23+
<Field label="Example field" validationState="success">
2824
<ProgressBar value={0.5} max={1} />
2925
</Field>
3026
```
3127

3228
```jsx
33-
<Field
34-
validationState="success"
35-
hint="This is a hint."
36-
>
29+
<Field validationState="success" hint="This is a hint.">
3730
<ProgressBar value={0.5} max={1} />
3831
</Field>
3932
```
4033

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

4336
```jsx
44-
<Field
45-
label="Example field"
46-
validationState="success"
47-
validationMessage="This is a success message."
48-
>
37+
<Field label="Example field">
38+
<Input />
39+
</Field>
40+
```
41+
42+
```jsx
43+
<Field label="Example field" validationState="success" validationMessage="This is a success message.">
4944
<ProgressBar value={0.5} max={1} />
5045
</Field>
5146
```
5247

5348
```jsx
54-
<Field
55-
label="Example field"
56-
validationState="success"
57-
hint="This is a hint."
58-
>
49+
<Field label="Example field" validationState="success" hint="This is a hint.">
5950
<ProgressBar value={0.5} max={1} />
6051
</Field>
6152
```

docs/rules/visual-label-better-than-aria-suggestion.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Visual label is better than an aria-label (`@microsoft/fluentui-jsx-a11y/visual-label-better-than-aria-suggestion`)
1+
# Visual label is better than an aria-label because sighted users can't read the aria-label text (`@microsoft/fluentui-jsx-a11y/visual-label-better-than-aria-suggestion`)
22

33
⚠️ This rule _warns_ in the ✅ `recommended` config.
44

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const labelBasedComponents = ["Label", "label"];
2+
const elementsUsedAsLabels = ["div", "span", "p", "h1", "h2", "h3", "h4", "h5", "h6"];
3+
4+
export { labelBasedComponents, elementsUsedAsLabels };

lib/rules/field-needs-labelling.js lib/rules/field-needs-labelling.ts

+11-10
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,41 @@
55

66
const { hasNonEmptyProp } = require("../util/hasNonEmptyProp");
77
const elementType = require("jsx-ast-utils").elementType;
8+
import { ESLintUtils, TSESTree } from "@typescript-eslint/utils";
89

910
//------------------------------------------------------------------------------
1011
// Rule Definition
1112
//------------------------------------------------------------------------------
1213

13-
module.exports = {
14+
const rule = ESLintUtils.RuleCreator.withoutDocs({
15+
defaultOptions: [],
1416
meta: {
1517
// possible error messages for the rule
1618
messages: {
17-
noUnlabelledField: "Accessibility: Field must have either label, validationMessage and hint attributes"
19+
noUnlabelledField: "Accessibility: Field must have label"
1820
},
1921
// "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
2022
type: "problem",
2123
// docs for the rule
2224
docs: {
23-
description: "Accessibility: Field must have either label, validationMessage and hint attributes",
24-
recommended: true,
25+
description: "Accessibility: Field must have label",
26+
recommended: "strict",
2527
url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule
2628
},
2729
schema: []
2830
},
31+
2932
// create (function) returns an object with methods that ESLint calls to “visit” nodes while traversing the abstract syntax tree
3033
create(context) {
3134
return {
3235
// visitor functions for different types of nodes
33-
JSXOpeningElement(node) {
36+
JSXOpeningElement(node: TSESTree.JSXOpeningElement) {
3437
// if it is not a Spinner, return
3538
if (elementType(node) !== "Field") {
3639
return;
3740
}
3841

39-
if (
40-
hasNonEmptyProp(node.attributes, "label", true) &&
41-
(hasNonEmptyProp(node.attributes, "validationMessage", true) || hasNonEmptyProp(node.attributes, "hint", true))
42-
) {
42+
if (hasNonEmptyProp(node.attributes, "label")) {
4343
return;
4444
}
4545

@@ -51,5 +51,6 @@ module.exports = {
5151
}
5252
};
5353
}
54-
};
54+
});
5555

56+
export default rule;

lib/rules/input-components-require-accessible-name.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { isInsideLabelTag, hasAssociatedLabelViaHtmlFor, hasAssociatedLabelViaAr
77
import { hasFieldParent } from "../util/hasFieldParent";
88
import { applicableComponents } from "../applicableComponents/inputBasedComponents";
99
import { JSXOpeningElement } from "estree-jsx";
10+
import { hasNonEmptyProp } from "../util/hasNonEmptyProp";
1011

1112
//------------------------------------------------------------------------------
1213
// Rule Definition
@@ -17,7 +18,7 @@ const rule = ESLintUtils.RuleCreator.withoutDocs({
1718
meta: {
1819
// possible error messages for the rule
1920
messages: {
20-
missingLabelOnInput: `Accessibility - input fields must have a aria label associated with it: ${applicableComponents.join(
21+
missingLabelOnInput: `Accessibility - input fields must have an accessible label associated with it: ${applicableComponents.join(
2122
", "
2223
)}`
2324
},
@@ -43,6 +44,7 @@ const rule = ESLintUtils.RuleCreator.withoutDocs({
4344

4445
// wrapped in Label tag, labelled with htmlFor, labelled with aria-labelledby
4546
if (
47+
hasNonEmptyProp(node.attributes, "aria-label") ||
4648
hasFieldParent(context) ||
4749
isInsideLabelTag(context) ||
4850
hasAssociatedLabelViaHtmlFor(node, context) ||

lib/rules/tablist-and-tabs-need-labelling.js

-76
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
import { ESLintUtils, TSESTree } from "@typescript-eslint/utils";
5+
import { hasTextContentChild } from "../util/hasTextContentChild";
6+
import { hasNonEmptyProp } from "../util/hasNonEmptyProp";
7+
import { hasAssociatedLabelViaAriaLabelledBy } from "../util/labelUtils";
8+
import { elementType } from "jsx-ast-utils";
9+
import { JSXOpeningElement } from "estree-jsx";
10+
11+
//------------------------------------------------------------------------------
12+
// Rule Definition
13+
//------------------------------------------------------------------------------
14+
15+
const rule = ESLintUtils.RuleCreator.withoutDocs({
16+
defaultOptions: [],
17+
meta: {
18+
type: "problem",
19+
docs: {
20+
description:
21+
"This rule aims to ensure that Tabs with icons but no text labels have an accessible name and that Tablist is properly labeled.",
22+
recommended: "strict",
23+
url: "https://www.w3.org/WAI/ARIA/apg/patterns/tabs/" // URL to the documentation page for this rule
24+
},
25+
fixable: undefined,
26+
schema: [],
27+
messages: {
28+
missingTabLabel: "Accessibility: Tab elements must have an aria-label attribute is there is no visiable text content",
29+
missingTablistLabel: "Accessibility: Tablist must have an accessible label"
30+
}
31+
},
32+
33+
create(context) {
34+
return {
35+
// visitor functions for different types of nodes
36+
JSXOpeningElement(node: TSESTree.JSXOpeningElement) {
37+
const elementTypeValue = elementType(node as unknown as JSXOpeningElement);
38+
39+
// if it is not a Tablist or Tab, return
40+
if (elementTypeValue !== "Tablist" && elementTypeValue !== "Tab") {
41+
return;
42+
}
43+
44+
// Check for Tablist elements
45+
if (elementTypeValue === "Tablist") {
46+
if (
47+
// if the Tablist has a label, if the Tablist has an associated label, return
48+
hasNonEmptyProp(node.attributes, "aria-label") || //aria-label
49+
hasAssociatedLabelViaAriaLabelledBy(node, context) // aria-labelledby
50+
) {
51+
return;
52+
}
53+
context.report({
54+
node,
55+
messageId: "missingTablistLabel"
56+
});
57+
}
58+
59+
// Check for Tab elements
60+
if (elementTypeValue === "Tab") {
61+
if (
62+
hasTextContentChild(node.parent as unknown as TSESTree.JSXElement) || // text content
63+
hasNonEmptyProp(node.attributes, "aria-label") // aria-label
64+
) {
65+
return;
66+
}
67+
context.report({
68+
node,
69+
messageId: "missingTabLabel"
70+
});
71+
}
72+
}
73+
};
74+
}
75+
});
76+
77+
export default rule;

0 commit comments

Comments
 (0)