Skip to content

Commit

Permalink
Merge pull request #132 from microsoft/user/aubreyquinn/tsConverstion
Browse files Browse the repository at this point in the history
User/aubreyquinn/ts converstion
  • Loading branch information
aubreyquinn authored Nov 8, 2024
2 parents 362a590 + 536ae9f commit 26e7195
Show file tree
Hide file tree
Showing 34 changed files with 1,304 additions and 550 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,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 | ✅ | | |
| [field-needs-labelling](docs/rules/field-needs-labelling.md) | Accessibility: Field must have 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 | ✅ | | |
| [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 All @@ -141,6 +141,6 @@ Any use of third-party trademarks or logos are subject to those third-party's po
| [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. | ✅ | | |
| [toolbar-missing-aria](docs/rules/toolbar-missing-aria.md) | Accessibility: Toolbars need accessible labelling: aria-label or aria-labelledby | ✅ | | |
| [tooltip-not-recommended](docs/rules/tooltip-not-recommended.md) | Accessibility: Prefer text content or aria over a tooltip for these components MenuItem, SpinButton | ✅ | | |
| [visual-label-better-than-aria-suggestion](docs/rules/visual-label-better-than-aria-suggestion.md) | Visual label is better than an aria-label | | ✅ | |
| [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. | | ✅ | |

<!-- end auto-generated rules list -->
33 changes: 12 additions & 21 deletions docs/rules/field-needs-labelling.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
# Accessibility: Field must have either label, validationMessage and hint attributes (`@microsoft/fluentui-jsx-a11y/field-needs-labelling`)
# Accessibility: Field must have label (`@microsoft/fluentui-jsx-a11y/field-needs-labelling`)

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

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

Field must have `label` prop and either `validationMessage` or `hint` prop.
Field must have `label` prop.

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

## Ways to fix

- Make sure that Field component has following props:
- `label`
- `validationMessage` or `hint`

## Rule Details

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

```jsx
<Field
label="Example field"
validationState="success"
>
<Field label="Example field" validationState="success">
<ProgressBar value={0.5} max={1} />
</Field>
```

```jsx
<Field
validationState="success"
hint="This is a hint."
>
<Field validationState="success" hint="This is a hint.">
<ProgressBar value={0.5} max={1} />
</Field>
```

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

```jsx
<Field
label="Example field"
validationState="success"
validationMessage="This is a success message."
>
<Field label="Example field">
<Input />
</Field>
```

```jsx
<Field label="Example field" validationState="success" validationMessage="This is a success message.">
<ProgressBar value={0.5} max={1} />
</Field>
```

```jsx
<Field
label="Example field"
validationState="success"
hint="This is a hint."
>
<Field label="Example field" validationState="success" hint="This is a hint.">
<ProgressBar value={0.5} max={1} />
</Field>
```
2 changes: 1 addition & 1 deletion docs/rules/visual-label-better-than-aria-suggestion.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Visual label is better than an aria-label (`@microsoft/fluentui-jsx-a11y/visual-label-better-than-aria-suggestion`)
# 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`)

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

Expand Down
4 changes: 4 additions & 0 deletions lib/applicableComponents/labelBasedComponents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const labelBasedComponents = ["Label", "label"];
const elementsUsedAsLabels = ["div", "span", "p", "h1", "h2", "h3", "h4", "h5", "h6"];

export { labelBasedComponents, elementsUsedAsLabels };
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,41 @@

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

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

module.exports = {
const rule = ESLintUtils.RuleCreator.withoutDocs({
defaultOptions: [],
meta: {
// possible error messages for the rule
messages: {
noUnlabelledField: "Accessibility: Field must have either label, validationMessage and hint attributes"
noUnlabelledField: "Accessibility: Field must have 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 for the rule
docs: {
description: "Accessibility: Field must have either label, validationMessage and hint attributes",
recommended: true,
description: "Accessibility: Field must have label",
recommended: "strict",
url: "https://www.w3.org/TR/html-aria/" // URL to the documentation page for this rule
},
schema: []
},

// create (function) returns an object with methods that ESLint calls to “visit” nodes while traversing the abstract syntax tree
create(context) {
return {
// visitor functions for different types of nodes
JSXOpeningElement(node) {
JSXOpeningElement(node: TSESTree.JSXOpeningElement) {
// if it is not a Spinner, return
if (elementType(node) !== "Field") {
return;
}

if (
hasNonEmptyProp(node.attributes, "label", true) &&
(hasNonEmptyProp(node.attributes, "validationMessage", true) || hasNonEmptyProp(node.attributes, "hint", true))
) {
if (hasNonEmptyProp(node.attributes, "label")) {
return;
}

Expand All @@ -51,5 +51,6 @@ module.exports = {
}
};
}
};
});

export default rule;
4 changes: 3 additions & 1 deletion lib/rules/input-components-require-accessible-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { isInsideLabelTag, hasAssociatedLabelViaHtmlFor, hasAssociatedLabelViaAr
import { hasFieldParent } from "../util/hasFieldParent";
import { applicableComponents } from "../applicableComponents/inputBasedComponents";
import { JSXOpeningElement } from "estree-jsx";
import { hasNonEmptyProp } from "../util/hasNonEmptyProp";

//------------------------------------------------------------------------------
// Rule Definition
Expand All @@ -17,7 +18,7 @@ const rule = ESLintUtils.RuleCreator.withoutDocs({
meta: {
// possible error messages for the rule
messages: {
missingLabelOnInput: `Accessibility - input fields must have a aria label associated with it: ${applicableComponents.join(
missingLabelOnInput: `Accessibility - input fields must have an accessible label associated with it: ${applicableComponents.join(
", "
)}`
},
Expand All @@ -43,6 +44,7 @@ const rule = ESLintUtils.RuleCreator.withoutDocs({

// wrapped in Label tag, labelled with htmlFor, labelled with aria-labelledby
if (
hasNonEmptyProp(node.attributes, "aria-label") ||
hasFieldParent(context) ||
isInsideLabelTag(context) ||
hasAssociatedLabelViaHtmlFor(node, context) ||
Expand Down
76 changes: 0 additions & 76 deletions lib/rules/tablist-and-tabs-need-labelling.js

This file was deleted.

77 changes: 77 additions & 0 deletions lib/rules/tablist-and-tabs-need-labelling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { ESLintUtils, TSESTree } from "@typescript-eslint/utils";
import { hasTextContentChild } from "../util/hasTextContentChild";
import { hasNonEmptyProp } from "../util/hasNonEmptyProp";
import { hasAssociatedLabelViaAriaLabelledBy } from "../util/labelUtils";
import { elementType } from "jsx-ast-utils";
import { JSXOpeningElement } from "estree-jsx";

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

const rule = ESLintUtils.RuleCreator.withoutDocs({
defaultOptions: [],
meta: {
type: "problem",
docs: {
description:
"This rule aims to ensure that Tabs with icons but no text labels have an accessible name and that Tablist is properly labeled.",
recommended: "strict",
url: "https://www.w3.org/WAI/ARIA/apg/patterns/tabs/" // URL to the documentation page for this rule
},
fixable: undefined,
schema: [],
messages: {
missingTabLabel: "Accessibility: Tab elements must have an aria-label attribute is there is no visiable text content",
missingTablistLabel: "Accessibility: Tablist must have an accessible label"
}
},

create(context) {
return {
// visitor functions for different types of nodes
JSXOpeningElement(node: TSESTree.JSXOpeningElement) {
const elementTypeValue = elementType(node as unknown as JSXOpeningElement);

// if it is not a Tablist or Tab, return
if (elementTypeValue !== "Tablist" && elementTypeValue !== "Tab") {
return;
}

// Check for Tablist elements
if (elementTypeValue === "Tablist") {
if (
// if the Tablist has a label, if the Tablist has an associated label, return
hasNonEmptyProp(node.attributes, "aria-label") || //aria-label
hasAssociatedLabelViaAriaLabelledBy(node, context) // aria-labelledby
) {
return;
}
context.report({
node,
messageId: "missingTablistLabel"
});
}

// Check for Tab elements
if (elementTypeValue === "Tab") {
if (
hasTextContentChild(node.parent as unknown as TSESTree.JSXElement) || // text content
hasNonEmptyProp(node.attributes, "aria-label") // aria-label
) {
return;
}
context.report({
node,
messageId: "missingTabLabel"
});
}
}
};
}
});

export default rule;
Loading

0 comments on commit 26e7195

Please sign in to comment.