Skip to content

Commit a19b6cb

Browse files
authored
fix(aria-required-children): trigger reviewEmpty with hidden children (#4012)
* fix(aria-required-children): trigger reviewEmpty with hidden children * 🤖 Automated formatting fixes * Fix code block
1 parent 704043e commit a19b6cb

4 files changed

Lines changed: 115 additions & 233 deletions

File tree

lib/checks/aria/aria-required-children-evaluate.js

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
import { getGlobalAriaAttrs } from '../../commons/standards';
88
import {
99
hasContentVirtual,
10-
idrefs,
1110
isFocusable,
1211
isVisibleToScreenReaders
1312
} from '../../commons/dom';
@@ -35,7 +34,7 @@ export default function ariaRequiredChildrenEvaluate(
3534
return true;
3635
}
3736

38-
const ownedRoles = getOwnedRoles(virtualNode, required);
37+
const { ownedRoles, ownedElements } = getOwnedRoles(virtualNode, required);
3938
const unallowed = ownedRoles.filter(({ role }) => !required.includes(role));
4039

4140
if (unallowed.length) {
@@ -65,12 +64,7 @@ export default function ariaRequiredChildrenEvaluate(
6564
this.data(missing);
6665

6766
// Only review empty nodes when a node is both empty and does not have an aria-owns relationship
68-
if (
69-
reviewEmpty.includes(role) &&
70-
!hasContentVirtual(virtualNode, false, true) &&
71-
!ownedRoles.length &&
72-
(!virtualNode.hasAttr('aria-owns') || !idrefs(node, 'aria-owns').length)
73-
) {
67+
if (reviewEmpty.includes(role) && !ownedElements.some(isContent)) {
7468
return undefined;
7569
}
7670

@@ -82,7 +76,10 @@ export default function ariaRequiredChildrenEvaluate(
8276
*/
8377
function getOwnedRoles(virtualNode, required) {
8478
const ownedRoles = [];
85-
const ownedElements = getOwnedVirtual(virtualNode);
79+
const ownedElements = getOwnedVirtual(virtualNode).filter(vNode => {
80+
return vNode.props.nodeType !== 1 || isVisibleToScreenReaders(vNode);
81+
});
82+
8683
for (let i = 0; i < ownedElements.length; i++) {
8784
const ownedElement = ownedElements[i];
8885
if (ownedElement.props.nodeType !== 1) {
@@ -100,7 +97,6 @@ function getOwnedRoles(virtualNode, required) {
10097
// this means intermediate roles between a required parent and
10198
// child will fail the check
10299
if (
103-
!isVisibleToScreenReaders(ownedElement) ||
104100
(!role && !hasGlobalAriaOrFocusable) ||
105101
(['group', 'rowgroup'].includes(role) &&
106102
required.some(requiredRole => requiredRole === role))
@@ -115,7 +111,7 @@ function getOwnedRoles(virtualNode, required) {
115111
}
116112
}
117113

118-
return ownedRoles;
114+
return { ownedRoles, ownedElements };
119115
}
120116

121117
/**
@@ -171,3 +167,15 @@ function getUnallowedSelector(vNode, attr) {
171167

172168
return nodeName;
173169
}
170+
171+
/**
172+
* Check if the node has content, or is itself content
173+
* @param {VirtualNode} vNode
174+
* @returns {Boolean}
175+
*/
176+
function isContent(vNode) {
177+
if (vNode.props.nodeType === 3) {
178+
return vNode.props.nodeValue.trim().length > 0;
179+
}
180+
return hasContentVirtual(vNode, false, true);
181+
}

lib/standards/aria-roles.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,12 @@ const ariaRoles = {
378378
type: 'widget',
379379
requiredContext: ['menu', 'menubar', 'group'],
380380
requiredAttrs: ['aria-checked'],
381-
allowedAttrs: ['aria-expanded', 'aria-posinset', 'aria-readonly', 'aria-setsize'],
381+
allowedAttrs: [
382+
'aria-expanded',
383+
'aria-posinset',
384+
'aria-readonly',
385+
'aria-setsize'
386+
],
382387
superclassRole: ['checkbox', 'menuitem'],
383388
accessibleNameRequired: true,
384389
nameFromContent: true,
@@ -388,7 +393,12 @@ const ariaRoles = {
388393
type: 'widget',
389394
requiredContext: ['menu', 'menubar', 'group'],
390395
requiredAttrs: ['aria-checked'],
391-
allowedAttrs: ['aria-expanded', 'aria-posinset', 'aria-readonly', 'aria-setsize'],
396+
allowedAttrs: [
397+
'aria-expanded',
398+
'aria-posinset',
399+
'aria-readonly',
400+
'aria-setsize'
401+
],
392402
superclassRole: ['menuitemcheckbox', 'radio'],
393403
accessibleNameRequired: true,
394404
nameFromContent: true,

0 commit comments

Comments
 (0)