[web] rename dialog to route to match the framework (#54228)
Rename "dialog" to "route" to match the framework. The ARIA role "dialog" is an implementation detail, and it might change if a better implementation comes along. The semantic node itself implements the framework's "route" concept.
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index df663d1..bbd92f1 100644
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -43014,7 +43014,6 @@
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/accessibility.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/checkable.dart + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/dialog.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/focusable.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/heading.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/image.dart + ../../../flutter/LICENSE
@@ -43023,6 +43022,7 @@
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/link.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/live_region.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/platform_view.dart + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/route.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/scrollable.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart + ../../../flutter/LICENSE
@@ -45903,7 +45903,6 @@
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/accessibility.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/checkable.dart
-FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/dialog.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/focusable.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/heading.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/image.dart
@@ -45912,6 +45911,7 @@
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/link.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/live_region.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/platform_view.dart
+FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/route.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/scrollable.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart
diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart
index b02fd59..cdf615a 100644
--- a/lib/web_ui/lib/src/engine.dart
+++ b/lib/web_ui/lib/src/engine.dart
@@ -145,7 +145,6 @@
export 'engine/scene_view.dart';
export 'engine/semantics/accessibility.dart';
export 'engine/semantics/checkable.dart';
-export 'engine/semantics/dialog.dart';
export 'engine/semantics/focusable.dart';
export 'engine/semantics/heading.dart';
export 'engine/semantics/image.dart';
@@ -154,6 +153,7 @@
export 'engine/semantics/link.dart';
export 'engine/semantics/live_region.dart';
export 'engine/semantics/platform_view.dart';
+export 'engine/semantics/route.dart';
export 'engine/semantics/scrollable.dart';
export 'engine/semantics/semantics.dart';
export 'engine/semantics/semantics_helper.dart';
diff --git a/lib/web_ui/lib/src/engine/semantics/dialog.dart b/lib/web_ui/lib/src/engine/semantics/dialog.dart
deleted file mode 100644
index 8489667..0000000
--- a/lib/web_ui/lib/src/engine/semantics/dialog.dart
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import '../dom.dart';
-import '../semantics.dart';
-import '../util.dart';
-
-/// Provides accessibility for routes, including dialogs and pop-up menus.
-class SemanticDialog extends SemanticRole {
- SemanticDialog(SemanticsObject semanticsObject) : super.blank(SemanticRoleKind.dialog, semanticsObject) {
- // The following behaviors can coexist with dialog. Generic `RouteName`
- // and `LabelAndValue` are not used by this role because when the dialog
- // names its own route an `aria-label` is used instead of `aria-describedby`.
- addFocusManagement();
- addLiveRegion();
-
- // When a route/dialog shows up it is expected that the screen reader will
- // focus on something inside it. There could be two possibilities:
- //
- // 1. The framework explicitly marked a node inside the dialog as focused
- // via the `isFocusable` and `isFocused` flags. In this case, the node
- // will request focus directly and there's nothing to do on top of that.
- // 2. No node inside the route takes focus explicitly. In this case, the
- // expectation is to look through all nodes in traversal order and focus
- // on the first one.
- semanticsObject.owner.addOneTimePostUpdateCallback(() {
- if (semanticsObject.owner.hasNodeRequestingFocus) {
- // Case 1: a node requested explicit focus. Nothing extra to do.
- return;
- }
-
- // Case 2: nothing requested explicit focus. Focus on the first descendant.
- _setDefaultFocus();
- });
- }
-
- void _setDefaultFocus() {
- semanticsObject.visitDepthFirstInTraversalOrder((SemanticsObject node) {
- final SemanticRole? role = node.semanticRole;
- if (role == null) {
- return true;
- }
-
- // If the node does not take focus (e.g. focusing on it does not make
- // sense at all). Despair not. Keep looking.
- final bool didTakeFocus = role.focusAsRouteDefault();
- return !didTakeFocus;
- });
- }
-
- @override
- void update() {
- super.update();
-
- // If semantic object corresponding to the dialog also provides the label
- // for itself it is applied as `aria-label`. See also [describeBy].
- if (semanticsObject.namesRoute) {
- final String? label = semanticsObject.label;
- assert(() {
- if (label == null || label.trim().isEmpty) {
- printWarning(
- 'Semantic node ${semanticsObject.id} had both scopesRoute and '
- 'namesRoute set, indicating a self-labelled dialog, but it is '
- 'missing the label. A dialog should be labelled either by setting '
- 'namesRoute on itself and providing a label, or by containing a '
- 'child node with namesRoute that can describe it with its content.'
- );
- }
- return true;
- }());
- setAttribute('aria-label', label ?? '');
- setAriaRole('dialog');
- }
- }
-
- /// Sets the description of this dialog based on a [RouteName] descendant
- /// node, unless the dialog provides its own label.
- void describeBy(RouteName routeName) {
- if (semanticsObject.namesRoute) {
- // The dialog provides its own label, which takes precedence.
- return;
- }
-
- setAriaRole('dialog');
- setAttribute(
- 'aria-describedby',
- routeName.semanticsObject.element.id,
- );
- }
-
- @override
- bool focusAsRouteDefault() {
- // Dialogs are the ones that look inside themselves to find elements to
- // focus on. It doesn't make sense to focus on the dialog itself.
- return false;
- }
-}
-
-/// Supplies a description for the nearest ancestor [SemanticDialog].
-///
-/// This role is assigned to nodes that have `namesRoute` set but not
-/// `scopesRoute`. When both flags are set the node only gets the [SemanticDialog] role.
-///
-/// If the ancestor dialog is missing, this role has no effect. It is up to the
-/// framework, widget, and app authors to make sure a route name is scoped under
-/// a route.
-class RouteName extends SemanticBehavior {
- RouteName(super.semanticsObject, super.owner);
-
- SemanticDialog? _dialog;
-
- @override
- void update() {
- // NOTE(yjbanov): this does not handle the case when the node structure
- // changes such that this RouteName is no longer attached to the same
- // dialog. While this is technically expressible using the semantics API,
- // after discussing this case with customers I decided that this case is not
- // interesting enough to support. A tree restructure like this is likely to
- // confuse screen readers, and it would add complexity to the engine's
- // semantics code. Since reparenting can be done with no update to either
- // the Dialog or RouteName we'd have to scan intermediate nodes for
- // structural changes.
- if (!semanticsObject.namesRoute) {
- return;
- }
-
- if (semanticsObject.isLabelDirty) {
- final SemanticDialog? dialog = _dialog;
- if (dialog != null) {
- // Already attached to a dialog, just update the description.
- dialog.describeBy(this);
- } else {
- // Setting the label for the first time. Wait for the DOM tree to be
- // established, then find the nearest dialog and update its label.
- semanticsObject.owner.addOneTimePostUpdateCallback(() {
- if (!isDisposed) {
- _lookUpNearestAncestorDialog();
- _dialog?.describeBy(this);
- }
- });
- }
- }
- }
-
- void _lookUpNearestAncestorDialog() {
- SemanticsObject? parent = semanticsObject.parent;
- while (parent != null && parent.semanticRole?.kind != SemanticRoleKind.dialog) {
- parent = parent.parent;
- }
- if (parent != null && parent.semanticRole?.kind == SemanticRoleKind.dialog) {
- _dialog = parent.semanticRole! as SemanticDialog;
- }
- }
-}
diff --git a/lib/web_ui/lib/src/engine/semantics/focusable.dart b/lib/web_ui/lib/src/engine/semantics/focusable.dart
index b3289e3..54bc0d4 100644
--- a/lib/web_ui/lib/src/engine/semantics/focusable.dart
+++ b/lib/web_ui/lib/src/engine/semantics/focusable.dart
@@ -254,14 +254,14 @@
// as it is subject to non-local effects. Let's say the framework decides
// that a semantics node is currently not focused. That would lead to
// changeFocus(false) to be called. However, what if this node is inside
- // a dialog, and nothing else in the dialog is focused. The Flutter
+ // a route, and nothing else in the route is focused? The Flutter
// framework expects that the screen reader will focus on the first (in
- // traversal order) focusable element inside the dialog and send a
+ // traversal order) focusable element inside the route and send a
// SemanticsAction.focus action. Screen readers on the web do not do
// that, and so the web engine has to implement this behavior directly. So
- // the dialog will look for a focusable element and request focus on it,
+ // the route will look for a focusable element and request focus on it,
// but now there may be a race between this method unsetting the focus and
- // the dialog requesting focus on the same element.
+ // the route requesting focus on the same element.
return;
}
diff --git a/lib/web_ui/lib/src/engine/semantics/route.dart b/lib/web_ui/lib/src/engine/semantics/route.dart
new file mode 100644
index 0000000..89052e6
--- /dev/null
+++ b/lib/web_ui/lib/src/engine/semantics/route.dart
@@ -0,0 +1,174 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import '../dom.dart';
+import '../semantics.dart';
+import '../util.dart';
+
+/// Denotes that all descendant nodes are inside a route.
+///
+/// Routes can include dialogs, pop-up menus, sub-screens, and more.
+///
+/// See also:
+///
+/// * [RouteName], which provides a description for this route in the absense
+/// of an explicit route label set on the route itself.
+class SemanticRoute extends SemanticRole {
+ SemanticRoute(SemanticsObject semanticsObject) : super.blank(SemanticRoleKind.route, semanticsObject) {
+ // The following behaviors can coexist with the route. Generic `RouteName`
+ // and `LabelAndValue` are not used by this role because when the route
+ // names its own route an `aria-label` is used instead of
+ // `aria-describedby`.
+ addFocusManagement();
+ addLiveRegion();
+
+ // When a route is pushed it is expected that the screen reader will focus
+ // on something inside it. There could be two possibilities:
+ //
+ // 1. The framework explicitly marked a node inside the route as focused
+ // via the `isFocusable` and `isFocused` flags. In this case, the node
+ // will request focus directly and there's nothing to do on top of that.
+ // 2. No node inside the route takes focus explicitly. In this case, the
+ // expectation is to look through all nodes in traversal order and focus
+ // on the first one.
+ semanticsObject.owner.addOneTimePostUpdateCallback(() {
+ if (semanticsObject.owner.hasNodeRequestingFocus) {
+ // Case 1: a node requested explicit focus. Nothing extra to do.
+ return;
+ }
+
+ // Case 2: nothing requested explicit focus. Focus on the first descendant.
+ _setDefaultFocus();
+ });
+ }
+
+ void _setDefaultFocus() {
+ semanticsObject.visitDepthFirstInTraversalOrder((SemanticsObject node) {
+ final SemanticRole? role = node.semanticRole;
+ if (role == null) {
+ return true;
+ }
+
+ // If the node does not take focus (e.g. focusing on it does not make
+ // sense at all). Despair not. Keep looking.
+ final bool didTakeFocus = role.focusAsRouteDefault();
+ return !didTakeFocus;
+ });
+ }
+
+ @override
+ void update() {
+ super.update();
+
+ // If semantic object corresponding to the route also provides the label for
+ // itself it is applied as `aria-label`. See also [describeBy].
+ if (semanticsObject.namesRoute) {
+ final String? label = semanticsObject.label;
+ assert(() {
+ if (label == null || label.trim().isEmpty) {
+ printWarning(
+ 'Semantic node ${semanticsObject.id} had both scopesRoute and '
+ 'namesRoute set, indicating a self-labelled route, but it is '
+ 'missing the label. A route should be labelled either by setting '
+ 'namesRoute on itself and providing a label, or by containing a '
+ 'child node with namesRoute that can describe it with its content.'
+ );
+ }
+ return true;
+ }());
+
+ setAttribute('aria-label', label ?? '');
+ _assignRole();
+ }
+ }
+
+ /// Sets the description of this route based on a [RouteName] descendant
+ /// node, unless the route provides its own label.
+ void describeBy(RouteName routeName) {
+ if (semanticsObject.namesRoute) {
+ // The route provides its own label, which takes precedence.
+ return;
+ }
+
+ _assignRole();
+ setAttribute(
+ 'aria-describedby',
+ routeName.semanticsObject.element.id,
+ );
+ }
+
+ void _assignRole() {
+ // Lacking any more specific information, ARIA role "dialog" is the
+ // closest thing to Flutter's route. This can be revisited if better
+ // options become available, especially if the framework volunteers more
+ // specific information about the route. Other attributes in the vicinity
+ // of routes include: "alertdialog", `aria-modal`, "menu", "tooltip".
+ setAriaRole('dialog');
+ }
+
+ @override
+ bool focusAsRouteDefault() {
+ // Routes are the ones that look inside themselves to find elements to
+ // focus on. It doesn't make sense to focus on the route itself.
+ return false;
+ }
+}
+
+/// Supplies a description for the nearest ancestor [SemanticRoute].
+///
+/// This role is assigned to nodes that have `namesRoute` set but not
+/// `scopesRoute`. When both flags are set the node only gets the
+/// [SemanticRoute] role.
+///
+/// If the ancestor route is missing, this role has no effect. It is up to the
+/// framework, widget, and app authors to make sure a route name is scoped
+/// under a route.
+class RouteName extends SemanticBehavior {
+ RouteName(super.semanticsObject, super.owner);
+
+ SemanticRoute? _route;
+
+ @override
+ void update() {
+ // NOTE(yjbanov): this does not handle the case when the node structure
+ // changes such that this RouteName is no longer attached to the same route.
+ // While this is technically expressible using the semantics API, after
+ // discussing this case with customers I decided that this case is not
+ // interesting enough to support. A tree restructure like this is likely to
+ // confuse screen readers, and it would add complexity to the engine's
+ // semantics code. Since reparenting can be done with no update to either
+ // the SemanticRoute or RouteName we'd have to scan intermediate nodes
+ // for structural changes.
+ if (!semanticsObject.namesRoute) {
+ return;
+ }
+
+ if (semanticsObject.isLabelDirty) {
+ final SemanticRoute? route = _route;
+ if (route != null) {
+ // Already attached to a route, just update the description.
+ route.describeBy(this);
+ } else {
+ // Setting the label for the first time. Wait for the DOM tree to be
+ // established, then find the nearest route and update its label.
+ semanticsObject.owner.addOneTimePostUpdateCallback(() {
+ if (!isDisposed) {
+ _lookUpNearestAncestorRoute();
+ _route?.describeBy(this);
+ }
+ });
+ }
+ }
+ }
+
+ void _lookUpNearestAncestorRoute() {
+ SemanticsObject? parent = semanticsObject.parent;
+ while (parent != null && parent.semanticRole?.kind != SemanticRoleKind.route) {
+ parent = parent.parent;
+ }
+ if (parent != null && parent.semanticRole?.kind == SemanticRoleKind.route) {
+ _route = parent.semanticRole! as SemanticRoute;
+ }
+ }
+}
diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart
index a35651b..9b7135c 100644
--- a/lib/web_ui/lib/src/engine/semantics/semantics.dart
+++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart
@@ -20,7 +20,6 @@
import '../window.dart';
import 'accessibility.dart';
import 'checkable.dart';
-import 'dialog.dart';
import 'focusable.dart';
import 'heading.dart';
import 'image.dart';
@@ -29,6 +28,7 @@
import 'link.dart';
import 'live_region.dart';
import 'platform_view.dart';
+import 'route.dart';
import 'scrollable.dart';
import 'semantics_helper.dart';
import 'tappable.dart';
@@ -379,19 +379,19 @@
/// There are 3 possible situations:
///
/// * The node also has the `namesRoute` bit set. This means that the node's
- /// `label` describes the dialog, which can be expressed by adding the
+ /// `label` describes the route, which can be expressed by adding the
/// `aria-label` attribute.
/// * A descendant node has the `namesRoute` bit set. This means that the
- /// child's content describes the dialog. The child may simply be labelled,
- /// or it may be a subtree of nodes that describe the dialog together. The
+ /// child's content describes the route. The child may simply be labelled,
+ /// or it may be a subtree of nodes that describe the route together. The
/// nearest HTML equivalent is `aria-describedby`. The child acquires the
/// [routeName] role, which manages the relevant ARIA attributes.
/// * There is no `namesRoute` bit anywhere in the sub-tree rooted at the
- /// current node. In this case it's likely not a dialog at all, and the node
+ /// current node. In this case it's likely not a route at all, and the node
/// should not get a label or the "dialog" role. It's just a group of
/// children. For example, a modal barrier has `scopesRoute` set but marking
- /// it as a dialog would be wrong.
- dialog,
+ /// it as a route would be wrong.
+ route,
/// The node's role is to host a platform view.
platformView,
@@ -1653,7 +1653,7 @@
} else if (isScrollContainer) {
return SemanticRoleKind.scrollable;
} else if (scopesRoute) {
- return SemanticRoleKind.dialog;
+ return SemanticRoleKind.route;
} else if (isLink) {
return SemanticRoleKind.link;
} else {
@@ -1668,7 +1668,7 @@
SemanticRoleKind.incrementable => SemanticIncrementable(this),
SemanticRoleKind.button => SemanticButton(this),
SemanticRoleKind.checkable => SemanticCheckable(this),
- SemanticRoleKind.dialog => SemanticDialog(this),
+ SemanticRoleKind.route => SemanticRoute(this),
SemanticRoleKind.image => SemanticImage(this),
SemanticRoleKind.platformView => SemanticPlatformView(this),
SemanticRoleKind.link => SemanticLink(this),
diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart
index 5c5e25f..e55fc2c 100644
--- a/lib/web_ui/test/engine/semantics/semantics_test.dart
+++ b/lib/web_ui/test/engine/semantics/semantics_test.dart
@@ -102,8 +102,8 @@
group('group', () {
_testGroup();
});
- group('dialog', () {
- _testDialog();
+ group('route', () {
+ _testRoute();
});
group('focusable', () {
_testFocusable();
@@ -2970,7 +2970,7 @@
});
}
-void _testDialog() {
+void _testRoute() {
test('renders named and labeled routes', () {
semantics()
..debugOverrideTimestampFunction(() => _testTime)
@@ -2979,7 +2979,7 @@
final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder();
updateNode(
builder,
- label: 'this is a dialog label',
+ label: 'this is a route label',
flags: 0 | ui.SemanticsFlag.scopesRoute.index | ui.SemanticsFlag.namesRoute.index,
transform: Matrix4.identity().toFloat64(),
rect: const ui.Rect.fromLTRB(0, 0, 100, 50),
@@ -2995,12 +2995,12 @@
owner().updateSemantics(builder.build());
expectSemanticsTree(owner(), '''
- <sem role="dialog" aria-label="this is a dialog label"><sem-c><sem></sem></sem-c></sem>
+ <sem role="dialog" aria-label="this is a route label"><sem-c><sem></sem></sem-c></sem>
''');
expect(
owner().debugSemanticsTree![0]!.semanticRole?.kind,
- SemanticRoleKind.dialog,
+ SemanticRoleKind.route,
);
semantics().semanticsEnabled = false;
@@ -3034,7 +3034,7 @@
expect(
warnings,
<String>[
- 'Semantic node 0 had both scopesRoute and namesRoute set, indicating a self-labelled dialog, but it is missing the label. A dialog should be labelled either by setting namesRoute on itself and providing a label, or by containing a child node with namesRoute that can describe it with its content.',
+ 'Semantic node 0 had both scopesRoute and namesRoute set, indicating a self-labelled route, but it is missing the label. A route should be labelled either by setting namesRoute on itself and providing a label, or by containing a child node with namesRoute that can describe it with its content.',
],
);
@@ -3045,13 +3045,13 @@
expect(
owner().debugSemanticsTree![0]!.semanticRole?.kind,
- SemanticRoleKind.dialog,
+ SemanticRoleKind.route,
);
semantics().semanticsEnabled = false;
});
- test('dialog can be described by a descendant', () {
+ test('route can be described by a descendant', () {
semantics()
..debugOverrideTimestampFunction(() => _testTime)
..semanticsEnabled = true;
@@ -3090,11 +3090,11 @@
''');
}
- pumpSemantics(label: 'Dialog label');
+ pumpSemantics(label: 'Route label');
expect(
owner().debugSemanticsTree![0]!.semanticRole?.kind,
- SemanticRoleKind.dialog,
+ SemanticRoleKind.route,
);
expect(
owner().debugSemanticsTree![2]!.semanticRole?.kind,
@@ -3105,12 +3105,12 @@
contains(RouteName),
);
- pumpSemantics(label: 'Updated dialog label');
+ pumpSemantics(label: 'Updated route label');
semantics().semanticsEnabled = false;
});
- test('scopesRoute alone sets the dialog role with no label', () {
+ test('scopesRoute alone sets the SemanticRoute role with no label', () {
final List<String> warnings = <String>[];
printWarning = warnings.add;
@@ -3132,7 +3132,7 @@
expect(
owner().debugSemanticsTree![0]!.semanticRole?.kind,
- SemanticRoleKind.dialog,
+ SemanticRoleKind.route,
);
expect(
owner().debugSemanticsTree![0]!.semanticRole?.behaviors,
@@ -3190,7 +3190,7 @@
semantics().semanticsEnabled = false;
});
- // Test the simple scenario of a dialog coming up and containing focusable
+ // Test the simple scenario of a route coming up and containing focusable
// descendants that are not initially focused. The expectation is that the
// first descendant will be auto-focused.
test('focuses on the first unfocused Focusable', () async {
@@ -3248,9 +3248,9 @@
semantics().semanticsEnabled = false;
});
- // Test the scenario of a dialog coming up and containing focusable
+ // Test the scenario of a route coming up and containing focusable
// descendants with one of them explicitly requesting focus. The expectation
- // is that the dialog will not attempt to auto-focus on anything and let the
+ // is that the route will not attempt to auto-focus on anything and let the
// respective descendant take focus.
test('does nothing if a descendant asks for focus explicitly', () async {
semantics()
@@ -3306,7 +3306,7 @@
semantics().semanticsEnabled = false;
});
- // Test the scenario of a dialog coming up and containing non-focusable
+ // Test the scenario of a route coming up and containing non-focusable
// descendants that can have a11y focus. The expectation is that the first
// descendant will be auto-focused, even if it's not input-focusable.
test('focuses on the first non-focusable descedant', () async {
@@ -3378,8 +3378,8 @@
});
// This mostly makes sure the engine doesn't crash if given a completely empty
- // dialog trying to find something to focus on.
- test('does nothing if nothing is focusable inside the dialog', () async {
+ // route trying to find something to focus on.
+ test('does nothing if nothing is focusable inside the route', () async {
semantics()
..debugOverrideTimestampFunction(() => _testTime)
..semanticsEnabled = true;