@@ -21,6 +21,7 @@ import '../window.dart';
2121import 'accessibility.dart' ;
2222import 'checkable.dart' ;
2323import 'focusable.dart' ;
24+ import 'header.dart' ;
2425import 'heading.dart' ;
2526import 'image.dart' ;
2627import 'incrementable.dart' ;
@@ -396,14 +397,17 @@ enum SemanticRoleKind {
396397 /// The node's role is to host a platform view.
397398 platformView,
398399
400+ /// Contains a link.
401+ link,
402+
403+ /// Denotes a header.
404+ header,
405+
399406 /// A role used when a more specific role cannot be assigend to
400407 /// a [SemanticsObject] .
401408 ///
402409 /// Provides a label or a value.
403410 generic,
404-
405- /// Contains a link.
406- link,
407411}
408412
409413/// Responsible for setting the `role` ARIA attribute, for attaching
@@ -688,23 +692,18 @@ final class GenericRole extends SemanticRole {
688692 return ;
689693 }
690694
691- // Assign one of three roles to the element: group, heading, text.
695+ // Assign one of two roles to the element: group or text.
692696 //
693697 // - "group" is used when the node has children, irrespective of whether the
694698 // node is marked as a header or not. This is because marking a group
695699 // as a "heading" will prevent the AT from reaching its children.
696- // - "heading" is used when the framework explicitly marks the node as a
697- // heading and the node does not have children.
698700 // - If a node has a label and no children, assume is a paragraph of text.
699701 // In HTML text has no ARIA role. It's just a DOM node with text inside
700702 // it. Previously, role="text" was used, but it was only supported by
701703 // Safari, and it was removed starting Safari 17.
702704 if (semanticsObject.hasChildren) {
703705 labelAndValue! .preferredRepresentation = LabelRepresentation .ariaLabel;
704706 setAriaRole ('group' );
705- } else if (semanticsObject.hasFlag (ui.SemanticsFlag .isHeader)) {
706- labelAndValue! .preferredRepresentation = LabelRepresentation .domText;
707- setAriaRole ('heading' );
708707 } else {
709708 labelAndValue! .preferredRepresentation = LabelRepresentation .sizedSpan;
710709 removeAttribute ('role' );
@@ -1272,11 +1271,24 @@ class SemanticsObject {
12721271 bool get isTextField => hasFlag (ui.SemanticsFlag .isTextField);
12731272
12741273 /// Whether this object represents a heading element.
1274+ ///
1275+ /// Typically, a heading is a prominent piece of text that describes what the
1276+ /// rest of the screen or page is about.
1277+ ///
1278+ /// Not to be confused with [isHeader] .
12751279 bool get isHeading => headingLevel != 0 ;
12761280
1277- /// Whether this object represents an editable text field .
1281+ /// Whether this object represents an interactive link .
12781282 bool get isLink => hasFlag (ui.SemanticsFlag .isLink);
12791283
1284+ /// Whether this object represents a header.
1285+ ///
1286+ /// A header is a group of widgets that introduce the content of the screen
1287+ /// or a page.
1288+ ///
1289+ /// Not to be confused with [isHeading] .
1290+ bool get isHeader => hasFlag (ui.SemanticsFlag .isHeader);
1291+
12801292 /// Whether this object needs screen readers attention right away.
12811293 bool get isLiveRegion =>
12821294 hasFlag (ui.SemanticsFlag .isLiveRegion) &&
@@ -1690,6 +1702,8 @@ class SemanticsObject {
16901702 return SemanticRoleKind .route;
16911703 } else if (isLink) {
16921704 return SemanticRoleKind .link;
1705+ } else if (isHeader) {
1706+ return SemanticRoleKind .header;
16931707 } else {
16941708 return SemanticRoleKind .generic;
16951709 }
@@ -1707,6 +1721,7 @@ class SemanticsObject {
17071721 SemanticRoleKind .platformView => SemanticPlatformView (this ),
17081722 SemanticRoleKind .link => SemanticLink (this ),
17091723 SemanticRoleKind .heading => SemanticHeading (this ),
1724+ SemanticRoleKind .header => SemanticHeader (this ),
17101725 SemanticRoleKind .generic => GenericRole (this ),
17111726 };
17121727 }
0 commit comments