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

fix(aria-roles): correct abstract roles (types) for aria-roles #4421

Merged
merged 14 commits into from May 2, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions doc/standards-object.md
Expand Up @@ -67,9 +67,11 @@ The [`ariaRoles`](../lib/standards/aria-roles.js) object defines valid ARIA role

- `type` - string(required). [The role type](https://www.w3.org/TR/wai-aria-1.1/#roles_categorization). Valid types are:
- `abstract`
- `widget`
- `structure`
- `composite`
- `landmark`
- `structure`
- `widget`
- `window`
- `requiredContext` - array(optional). List of required parent roles.
- `requiredOwned` - array(optional). List of required owned roles.
- `requiredAttrs` - array(optional). List of required attributes.
Expand Down
26 changes: 26 additions & 0 deletions lib/checks/aria/has-widget-or-window-role-evaluate.js
@@ -0,0 +1,26 @@
import { getRoleType } from '../../commons/aria';

const acceptedRoles = {
widget: true,
composite: true,
window: true
};

/**
* Check if an elements `role` attribute uses any widget, composite, window abstract role values.
*
* Widget roles are taken from the `ariaRoles` standards object from the roles `type` property.
*
* @memberof checks
* @return {Boolean} True if the element uses a `widget`, `composite`, or `window` abstract role (type). False otherwise.
*/
// # TODO: change to abstract role for widget and window
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean by this. Is this supposed to be here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not intentional, reverted a07c488

function hasWidgetOrWindowRoleEvaluate(node) {
const role = node.getAttribute('role');
if (role === null) {
return false;
}
return !!acceptedRoles[getRoleType(role)];
}

export default hasWidgetOrWindowRoleEvaluate;
12 changes: 12 additions & 0 deletions lib/checks/aria/has-widget-or-window-role.json
@@ -0,0 +1,12 @@
{
"id": "has-widget-or-window-role",
"evaluate": "has-widget-or-window-role-evaluate",
"options": [],
"metadata": {
"impact": "minor",
"messages": {
"pass": "Element has a widget or window role.",
"fail": "Element does not have a widget or window role."
}
}
}
20 changes: 0 additions & 20 deletions lib/checks/aria/has-widget-role-evaluate.js

This file was deleted.

12 changes: 0 additions & 12 deletions lib/checks/aria/has-widget-role.json

This file was deleted.

2 changes: 1 addition & 1 deletion lib/rules/focus-order-semantics.json
Expand Up @@ -9,6 +9,6 @@
"help": "Elements in the focus order should have an appropriate role"
},
"all": [],
"any": ["has-widget-role", "valid-scrollable-semantics"],
"any": ["has-widget-or-window-role", "valid-scrollable-semantics"],
"none": []
}
17 changes: 10 additions & 7 deletions lib/standards/aria-roles.js
@@ -1,4 +1,5 @@
// Source: https://www.w3.org/TR/wai-aria-1.1/#roles
// Source for abstract roles (types): https://www.w3.org/TR/wai-aria/#abstract_roles

/* easiest way to see allowed roles is to filter out the global ones
from the list of inherited states and properties. The dpub spec
Expand All @@ -17,13 +18,13 @@
*/
const ariaRoles = {
alert: {
type: 'widget',
type: 'structure',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This creates a problem for focus-order-semantics. With this change, the following is going to start failing. I don't think we should want that.

<div role="alert" tabindex="0"> Hello world </div>

This is what we talked about on Thursday. We'll need some way to exempt these roles that are no longer considered as widgets in the focus-order-semantics rule. I think the best way to do that is just to add them to the VALID_ROLES_FOR_SCROLLABLE_REGIONS object in valid-scrollable-semantics-evaluate.

// Spec difference: Aria-expanded removed in 1.2
allowedAttrs: ['aria-expanded'],
superclassRole: ['section']
},
alertdialog: {
type: 'widget',
type: 'window',
straker marked this conversation as resolved.
Show resolved Hide resolved
// Spec difference: Aria-expanded removed in 1.2
allowedAttrs: ['aria-expanded', 'aria-modal'],
superclassRole: ['alert', 'dialog'],
Expand Down Expand Up @@ -119,6 +120,7 @@ const ariaRoles = {
nameFromContent: true
},
combobox: {
// Note: spec difference
type: 'widget',
requiredAttrs: ['aria-expanded', 'aria-controls'],
allowedAttrs: [
Expand Down Expand Up @@ -169,7 +171,7 @@ const ariaRoles = {
prohibitedAttrs: ['aria-label', 'aria-labelledby']
},
dialog: {
type: 'widget',
type: 'window',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably structure again as not a landmark

Suggested change
type: 'window',
type: 'structure',

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we said window is fine for alertdialog I assume it's fine here as well

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Ava. Since this is window in the spec, lets have it consistent.

// Spec difference: Aria-expanded removed in 1.2
allowedAttrs: ['aria-expanded', 'aria-modal'],
superclassRole: ['window'],
Expand Down Expand Up @@ -301,6 +303,7 @@ const ariaRoles = {
superclassRole: ['section']
},
listbox: {
// Note: spec difference
type: 'widget',
requiredOwned: ['group', 'option'],
allowedAttrs: [
Expand Down Expand Up @@ -328,7 +331,7 @@ const ariaRoles = {
nameFromContent: true
},
log: {
type: 'widget',
type: 'structure',
// Spec difference: Aria-expanded removed in 1.2
allowedAttrs: ['aria-expanded'],
superclassRole: ['section']
Expand All @@ -340,7 +343,7 @@ const ariaRoles = {
superclassRole: ['landmark']
},
marquee: {
type: 'widget',
type: 'structure',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you're adding roles to valid-scrollable-semantics, I think you can leave this one out. role=marquee doesn't seem like it should be focusable.

// Spec difference: Aria-expanded removed in 1.2
allowedAttrs: ['aria-expanded'],
superclassRole: ['section']
Expand Down Expand Up @@ -696,7 +699,7 @@ const ariaRoles = {
accessibleNameRequired: true
},
status: {
type: 'widget',
type: 'structure',
// Spec difference: Aria-expanded removed in 1.2
allowedAttrs: ['aria-expanded'],
superclassRole: ['section']
Expand Down Expand Up @@ -816,7 +819,7 @@ const ariaRoles = {
superclassRole: ['section']
},
timer: {
type: 'widget',
type: 'structure',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you're adding roles to valid-scrollable-semantics, I think you can leave this one out. role=timer doesn't seem like it should be focusable.

// Spec difference: Aria-expanded removed in 1.2
allowedAttrs: ['aria-expanded'],
superclassRole: ['status']
Expand Down
6 changes: 3 additions & 3 deletions locales/_template.json
Expand Up @@ -576,9 +576,9 @@
},
"fail": "Element does not have global ARIA attribute"
},
"has-widget-role": {
"pass": "Element has a widget role.",
"fail": "Element does not have a widget role."
"has-widget-or-window-role": {
"pass": "Element has a widget or window role.",
"fail": "Element does not have a widget or window role."
},
"invalidrole": {
"pass": "ARIA role is valid",
Expand Down
4 changes: 0 additions & 4 deletions locales/da.json
Expand Up @@ -365,10 +365,6 @@
"plural": "'aria-errormessage'-værdi ${data.values}` bør bruge en teknik til at annoncere beskeden (fx 'aria-live', 'aria-describedby', 'role=alert', osv.)"
}
},
"has-widget-role": {
"pass": "Elementet har en 'widget'-rolle.",
"fail": "Elementet har ikke en 'widget'-rolle."
},
"invalidrole": {
"pass": "ARIA-rollen er korrekt",
"fail": "Rollen skal være en af de mulige ARIA-roller"
Expand Down
4 changes: 0 additions & 4 deletions locales/de.json
Expand Up @@ -576,10 +576,6 @@
},
"fail": "Das Element hat keine globalen ARIA Attribute."
},
"has-widget-role": {
"pass": "Element hat eine widget-Rolle.",
"fail": "Das Element besitzt keine widget-Rolle."
},
"invalidrole": {
"pass": "ARIA Rolle ist gültig.",
"fail": {
Expand Down
4 changes: 0 additions & 4 deletions locales/el.json
Expand Up @@ -539,10 +539,6 @@
},
"fail": "Το στοιχείο δεν έχει καθολικό χαρακτηριστικό ARIA"
},
"has-widget-role": {
"pass": "Το στοιχείο έχει ρόλο widget.",
"fail": "Το στοιχείο δεν έχει ρόλο widget."
},
"invalidrole": {
"pass": "Ο ρόλος ARIA είναι έγκυρος",
"fail": {
Expand Down
4 changes: 0 additions & 4 deletions locales/es.json
Expand Up @@ -356,10 +356,6 @@
"plural": "En aria-errormessage, valor ${data.values}`, se debe usar una técnica para anunciar el mensaje (p. ej., aria-live, aria-describedby, role=alert, etc.)"
}
},
"has-widget-role": {
"pass": "El elemento tiene un rol de widget.",
"fail": "El elemento no tiene un rol de widget."
},
"invalidrole": {
"pass": "El rol ARIA es válido",
"fail": "El rol debe ser uno de los roles ARIA válidos"
Expand Down
4 changes: 0 additions & 4 deletions locales/eu.json
Expand Up @@ -356,10 +356,6 @@
"plural": "aria-errormessagen, bailioa ${data.values}`, mezua iragartzeko teknika bat erabili behar da (adibidez: aria-live, aria-describedby, role = alert, etab.)."
}
},
"has-widget-role": {
"pass": "Elementuak widget rola du.",
"fail": "Elementuak ez du widget rolik."
},
"invalidrole": {
"pass": "ARIA rola baliozkoa da",
"fail": "Rolak baliozko ARIA rola izan behar du"
Expand Down
4 changes: 0 additions & 4 deletions locales/fr.json
Expand Up @@ -519,10 +519,6 @@
},
"fail": "L’élément n’a pas d’attribut ARIA global"
},
"has-widget-role": {
"pass": "L’élément a un rôle widget.",
"fail": "L’élément n’a pas de rôle widget."
},
"invalidrole": {
"pass": "Le rôle ARIA est valide",
"fail": {
Expand Down
4 changes: 0 additions & 4 deletions locales/he.json
Expand Up @@ -529,10 +529,6 @@
},
"fail": "לאלמנט אין תכונת ARIA גלובלית: "
},
"has-widget-role": {
"pass": "לאלמנט יש תפקיד של וגדג'ט.",
"fail": "לאלמנט אין תפקיד של וגדג'ט."
},
"invalidrole": {
"pass": "תפקיד ARIA קביל",
"fail": {
Expand Down
4 changes: 0 additions & 4 deletions locales/it.json
Expand Up @@ -573,10 +573,6 @@
},
"fail": "L'elemento non ha un attributo ARIA globale"
},
"has-widget-role": {
"pass": "L'elemento ha un ruolo widget.",
"fail": "L'elemento non ha un ruolo widget."
},
"invalidrole": {
"pass": "Il ruolo ARIA è valido",
"fail": {
Expand Down
4 changes: 0 additions & 4 deletions locales/ja.json
Expand Up @@ -575,10 +575,6 @@
},
"fail": "要素にはグローバルなARIA属性が指定されていません"
},
"has-widget-role": {
"pass": "要素にはwidgetロールが存在します",
"fail": "要素にはwidgetロールが存在しません"
},
"invalidrole": {
"pass": "ARIAロールが有効です",
"fail": {
Expand Down
4 changes: 0 additions & 4 deletions locales/ko.json
Expand Up @@ -524,10 +524,6 @@
},
"fail": "엘리먼트가 전역 ARIA 어트리뷰트를 가지고 있지 않습니다."
},
"has-widget-role": {
"pass": "엘리먼트가 위젯 역할(role)을 가지고 있습니다.",
"fail": "엘리먼트가 위젯 역할(role)을 가지고 있지 않습니다."
},
"invalidrole": {
"pass": "ARIA 역할(role)이 유효합니다.",
"fail": {
Expand Down
4 changes: 0 additions & 4 deletions locales/no_NB.json
Expand Up @@ -365,10 +365,6 @@
"plural": "'aria-errormessage'-verdier ${data.values}` skal bruke en metode for å annonsere beskeden (f.eks. 'aria-live', 'aria-describedby', 'role=alert', osv.)"
}
},
"has-widget-role": {
"pass": "Elementet har en 'widget'-rolle.",
"fail": "Elementet har ikke en 'widget'-rolle."
},
"invalidrole": {
"pass": "ARIA-rollen er korrekt",
"fail": "Rollen skal være en av de mulige ARIA-roller"
Expand Down
4 changes: 0 additions & 4 deletions locales/pl.json
Expand Up @@ -575,10 +575,6 @@
},
"fail": "Element nie ma ogólnego atrybutu ARIA"
},
"has-widget-role": {
"pass": "Element ma rolę widżetu.",
"fail": "Element nie ma roli widżetu."
},
"invalidrole": {
"pass": "Rola ARIA jest poprawna.",
"fail": {
Expand Down
4 changes: 0 additions & 4 deletions locales/pt_BR.json
Expand Up @@ -504,10 +504,6 @@
},
"fail": "O elemento não tem atributo ARIA global"
},
"has-widget-role": {
"pass": "Elemento tem um 'role' de 'widget'.",
"fail": "Elemento não tem um 'role' de 'widget'."
},
"invalidrole": {
"pass": "O ARIA 'role' é válido",
"fail": {
Expand Down
4 changes: 0 additions & 4 deletions locales/zh_CN.json
Expand Up @@ -576,10 +576,6 @@
},
"fail": "元素没有全局 ARIA 属性"
},
"has-widget-role": {
"pass": "元素有小部件角色",
"fail": "元素没有小部件角色"
},
"invalidrole": {
"pass": "ARIA 角色有效",
"fail": {
Expand Down
4 changes: 0 additions & 4 deletions locales/zh_TW.json
Expand Up @@ -573,10 +573,6 @@
},
"fail": "元素沒有全域 ARIA 屬性"
},
"has-widget-role": {
"pass": "元素具有小部件角色",
"fail": "元素沒有小部件角色"
},
"invalidrole": {
"pass": "ARIA 角色有效",
"fail": {
Expand Down